summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--NEWS435
-rw-r--r--bus/.gitignore2
-rw-r--r--bus/Makefile.am83
-rw-r--r--bus/activation.c31
-rw-r--r--bus/apparmor.c1128
-rw-r--r--bus/apparmor.h66
-rw-r--r--bus/bus.c149
-rw-r--r--bus/bus.h12
-rw-r--r--bus/config-parser-common.c6
-rw-r--r--bus/config-parser-common.h3
-rw-r--r--bus/config-parser.c35
-rw-r--r--bus/connection.c343
-rw-r--r--bus/connection.h13
-rw-r--r--bus/dir-watch-inotify.c6
-rw-r--r--bus/dir-watch-kqueue.c18
-rw-r--r--bus/dispatch.c328
-rw-r--r--bus/driver.c444
-rw-r--r--bus/example-session-disable-stats.conf.in15
-rw-r--r--bus/example-system-enable-stats.conf.in15
-rw-r--r--bus/legacy-config/session.conf.in20
-rw-r--r--bus/legacy-config/system.conf.in20
-rw-r--r--bus/main.c38
-rw-r--r--bus/selinux.c4
-rw-r--r--bus/services.c7
-rw-r--r--bus/session.conf.in7
-rw-r--r--bus/signals.c198
-rw-r--r--bus/signals.h8
-rw-r--r--bus/stats.c117
-rw-r--r--bus/stats.h5
-rw-r--r--bus/system.conf.in28
-rw-r--r--bus/systemd-user/dbus.service.in11
-rw-r--r--bus/systemd-user/dbus.socket.in9
-rw-r--r--bus/test-main.c9
-rw-r--r--cmake/CMakeLists.txt76
-rw-r--r--cmake/ConfigureChecks.cmake47
-rw-r--r--cmake/bus/CMakeLists.txt46
-rw-r--r--cmake/bus/system.conf.cmake62
-rw-r--r--cmake/config.h.cmake90
-rw-r--r--cmake/dbus/CMakeLists.txt31
-rw-r--r--cmake/doc/CMakeLists.txt21
-rw-r--r--cmake/modules/MacrosAutotools.cmake90
-rw-r--r--cmake/test/CMakeLists.txt34
-rw-r--r--cmake/tools/CMakeLists.txt36
-rw-r--r--configure.ac209
-rw-r--r--dbus-1-uninstalled.pc.in13
-rw-r--r--dbus-1.pc.in13
-rw-r--r--dbus/Makefile.am51
-rw-r--r--dbus/Version.in10
-rw-r--r--dbus/dbus-asv-util.c54
-rw-r--r--dbus/dbus-asv-util.h4
-rw-r--r--dbus/dbus-auth-script.c15
-rw-r--r--dbus/dbus-auth-util.c1
-rw-r--r--dbus/dbus-auth.c77
-rw-r--r--dbus/dbus-auth.h15
-rw-r--r--dbus/dbus-connection-internal.h12
-rw-r--r--dbus/dbus-connection.c73
-rw-r--r--dbus/dbus-credentials-util.c1
-rw-r--r--dbus/dbus-credentials.c68
-rw-r--r--dbus/dbus-credentials.h22
-rw-r--r--dbus/dbus-errors.c30
-rw-r--r--dbus/dbus-file-unix.c4
-rw-r--r--dbus/dbus-file-win.c4
-rw-r--r--dbus/dbus-file.h2
-rw-r--r--dbus/dbus-hash.c6
-rw-r--r--dbus/dbus-hash.h75
-rw-r--r--dbus/dbus-internals.c69
-rw-r--r--dbus/dbus-internals.h54
-rw-r--r--dbus/dbus-keyring.c10
-rw-r--r--dbus/dbus-list.h27
-rw-r--r--dbus/dbus-macros.h22
-rw-r--r--dbus/dbus-mainloop.c92
-rw-r--r--dbus/dbus-marshal-basic.c8
-rw-r--r--dbus/dbus-marshal-basic.h6
-rw-r--r--dbus/dbus-marshal-byteswap.h1
-rw-r--r--dbus/dbus-marshal-header.h4
-rw-r--r--dbus/dbus-marshal-recursive-util.c2
-rw-r--r--dbus/dbus-marshal-recursive.h18
-rw-r--r--dbus/dbus-marshal-validate-util.c2
-rw-r--r--dbus/dbus-marshal-validate.h9
-rw-r--r--dbus/dbus-memory.c7
-rw-r--r--dbus/dbus-mempool.h4
-rw-r--r--dbus/dbus-message-internal.h12
-rw-r--r--dbus/dbus-message-private.h1
-rw-r--r--dbus/dbus-message-util.c78
-rw-r--r--dbus/dbus-message.c102
-rw-r--r--dbus/dbus-message.h11
-rw-r--r--dbus/dbus-misc.c6
-rw-r--r--dbus/dbus-nonce.c36
-rw-r--r--dbus/dbus-nonce.h7
-rw-r--r--dbus/dbus-object-tree.c2
-rw-r--r--dbus/dbus-pending-call-internal.h3
-rw-r--r--dbus/dbus-pipe.h7
-rw-r--r--dbus/dbus-protocol.h9
-rw-r--r--dbus/dbus-server-debug-pipe.c19
-rw-r--r--dbus/dbus-server-launchd.c5
-rw-r--r--dbus/dbus-server-protected.h6
-rw-r--r--dbus/dbus-server-socket.c52
-rw-r--r--dbus/dbus-server-socket.h6
-rw-r--r--dbus/dbus-server-unix.c101
-rw-r--r--dbus/dbus-server.c24
-rw-r--r--dbus/dbus-shared.h5
-rw-r--r--dbus/dbus-signature.c2
-rw-r--r--dbus/dbus-socket-set-epoll.c8
-rw-r--r--dbus/dbus-socket-set-poll.c22
-rw-r--r--dbus/dbus-socket-set.h19
-rw-r--r--dbus/dbus-sockets-win.h15
-rw-r--r--dbus/dbus-spawn-win.c22
-rw-r--r--dbus/dbus-spawn.c70
-rw-r--r--dbus/dbus-string.c34
-rw-r--r--dbus/dbus-string.h75
-rw-r--r--dbus/dbus-sysdeps-unix.c598
-rw-r--r--dbus/dbus-sysdeps-unix.h19
-rw-r--r--dbus/dbus-sysdeps-util-unix.c7
-rw-r--r--dbus/dbus-sysdeps-util-win.c277
-rw-r--r--dbus/dbus-sysdeps-win.c283
-rw-r--r--dbus/dbus-sysdeps-win.h8
-rw-r--r--dbus/dbus-sysdeps.c84
-rw-r--r--dbus/dbus-sysdeps.h225
-rw-r--r--dbus/dbus-test-main.c9
-rw-r--r--dbus/dbus-test.h43
-rw-r--r--dbus/dbus-threads-internal.h2
-rw-r--r--dbus/dbus-timeout.h4
-rw-r--r--dbus/dbus-transport-protected.h2
-rw-r--r--dbus/dbus-transport-socket.c87
-rw-r--r--dbus/dbus-transport-socket.h2
-rw-r--r--dbus/dbus-transport-unix.c18
-rw-r--r--dbus/dbus-transport.c29
-rw-r--r--dbus/dbus-transport.h5
-rw-r--r--dbus/dbus-userdb.h14
-rw-r--r--dbus/dbus-uuidgen.c16
-rw-r--r--dbus/dbus-uuidgen.h6
-rw-r--r--dbus/dbus-watch.c76
-rw-r--r--dbus/dbus-watch.h17
-rw-r--r--dbus/sd-daemon.c520
-rw-r--r--dbus/sd-daemon.h282
-rw-r--r--doc/.gitignore9
-rw-r--r--doc/Makefile.am37
-rw-r--r--doc/busconfig.dtd7
-rw-r--r--doc/dbus-api-design.duck888
-rw-r--r--doc/dbus-daemon.1.xml.in80
-rw-r--r--doc/dbus-launch.1.xml.in2
-rw-r--r--doc/dbus-monitor.1.xml.in19
-rw-r--r--doc/dbus-run-session.1.xml.in5
-rw-r--r--doc/dbus-specification.xml373
-rw-r--r--doc/dbus-test-tool.1.xml.in325
-rw-r--r--doc/dbus-tutorial.xml952
-rw-r--r--doc/dbus-update-activation-environment.1.xml.in213
-rw-r--r--m4/ld-version-script.m443
-rw-r--r--m4/visibility.m477
-rw-r--r--test/.gitignore3
-rw-r--r--test/Makefile.am316
-rw-r--r--test/corrupt.c13
-rw-r--r--test/data/systemd-activation/com.example.SystemdActivatable1.service4
-rw-r--r--test/data/systemd-activation/com.example.SystemdActivatable2.service4
-rw-r--r--test/data/systemd-activation/com.example.SystemdActivatable3.service4
-rw-r--r--test/data/systemd-activation/org.freedesktop.systemd1.service3
-rw-r--r--test/data/valid-config-files/.gitignore2
-rw-r--r--test/data/valid-config-files/finite-timeout.conf.in19
-rw-r--r--test/data/valid-config-files/forbidding.conf.in18
-rw-r--r--test/data/valid-config-files/listen-unix-runtime.conf11
-rw-r--r--test/data/valid-config-files/multi-user.conf.in15
-rw-r--r--test/data/valid-config-files/systemd-activation.conf.in11
-rw-r--r--test/dbus-daemon-eavesdrop.c172
-rw-r--r--test/dbus-daemon.c486
-rw-r--r--test/fdpass.c868
-rwxr-xr-xtest/glib-tap-test.sh13
-rw-r--r--test/internals/printf.c17
-rw-r--r--test/internals/refs.c11
-rw-r--r--test/internals/syslog.c9
-rw-r--r--test/loopback.c116
-rw-r--r--test/manual-authz.c2
-rw-r--r--test/manual-dir-iter.c92
-rw-r--r--test/manual-paths.c73
-rw-r--r--test/marshal.c4
-rw-r--r--test/monitor.c1523
-rw-r--r--test/name-test/Makefile.am39
-rwxr-xr-xtest/name-test/run-test-systemserver.sh89
-rwxr-xr-xtest/name-test/run-test.sh93
-rw-r--r--test/name-test/test-activation-forking.py6
-rw-r--r--test/name-test/test-threads-init.c10
-rwxr-xr-xtest/name-test/test-wait-for-echo.py6
-rw-r--r--test/relay.c11
-rw-r--r--test/sd-activation.c349
-rw-r--r--test/shell-test.c111
-rw-r--r--test/syntax.c4
-rw-r--r--test/tap-test.sh.in32
-rw-r--r--test/test-service.c8
-rw-r--r--test/test-utils-glib.c452
-rw-r--r--test/test-utils-glib.h94
-rw-r--r--test/test-utils.c55
-rw-r--r--test/test-utils.h17
-rw-r--r--test/uid-permissions.c199
-rw-r--r--tools/.gitignore1
-rwxr-xr-xtools/GetAllMatchRules.py112
-rw-r--r--tools/Makefile.am54
-rw-r--r--tools/dbus-echo.c246
-rw-r--r--tools/dbus-launch-win.c6
-rw-r--r--tools/dbus-launch.c102
-rw-r--r--tools/dbus-launch.h2
-rw-r--r--tools/dbus-monitor.c395
-rw-r--r--tools/dbus-print-message.c671
-rw-r--r--tools/dbus-print-message.h2
-rw-r--r--tools/dbus-send.c10
-rw-r--r--tools/dbus-spam.c524
-rw-r--r--tools/dbus-update-activation-environment.c423
-rw-r--r--tools/dbus-uuidgen.c7
-rw-r--r--tools/lcov.am4
-rw-r--r--tools/test-tool.c88
-rw-r--r--tools/test-tool.h31
-rw-r--r--tools/tool-common.c82
-rw-r--r--tools/tool-common.h38
212 files changed, 15532 insertions, 4314 deletions
diff --git a/.gitignore b/.gitignore
index 90de1394..8d746822 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
*.rej
*.o
*~
+/build-aux/
compile
config.cache
config.log
@@ -41,4 +42,5 @@ tags
/lcov.html/
/lcov.info
/lcov.info.tmp
+/tap-driver.sh
/test-driver
diff --git a/NEWS b/NEWS
index d323c003..d90f6c54 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,32 @@
-D-Bus 1.8.20 (UNRELEASED)
+D-Bus 1.9.18 (UNRELEASED)
==
+Configuration changes:
+
+• The basic setup for the well-known system and session buses is now done
+ in read-only files in ${datadir}, moving a step closer to systems
+ that can operate with an empty /etc directory. In increasing order
+ of precedence:
+
+ · ${datadir}/dbus-1/s*.conf now perform the basic setup such as setting
+ the default message policies.
+ · ${sysconfdir}/dbus-1/s*.conf are now optional. By default
+ dbus still installs a trivial version of each, for documentation
+ purposes; putting configuration directives in these files is deprecated.
+ · ${datadir}/dbus-1/s*.d/ are now available for third-party software
+ to install "drop-in" configuration snippets (any packages
+ using those directories should explicitly depend on at least this
+ version of dbus).
+ · ${sysconfdir}/dbus-1/s*.d/ are also still available for sysadmins
+ or third-party software to install "drop-in" configuration snippets
+ · ${sysconfdir}/dbus-1/s*-local.conf are still available for sysadmins'
+ overrides
+
+ ${datadir} is normally /usr/share, ${sysconfdir} is normally /etc,
+ and "s*" refers to either system or session as appropriate.
+
+ (fd.o #89280, Dimitri John Ledkov)
+
Fixes:
• Fix a memory leak when GetConnectionCredentials() succeeds
@@ -9,10 +35,15 @@ Fixes:
• Ensure that dbus-monitor does not reply to messages intended for others
(fd.o #90952, Simon McVittie)
-D-Bus 1.8.18 (2015-05-14)
+D-Bus 1.9.16 (2015-05-14)
==
-The “unicorn rifts” release.
+The “titanium barns” release.
+
+Dependencies:
+
+• Automake 1.13 is now required when compiling from git or modifying
+ the build system.
Security hardening:
@@ -21,11 +52,7 @@ Security hardening:
credentials-passing), as was already done for the system bus.
This avoids falling back to DBUS_COOKIE_SHA1, which relies on strongly
- unpredictable pseudo-random numbers; under certain circumstances
- (/dev/urandom unreadable or malloc() returns NULL), dbus could
- fall back to using rand(), which does not have the desired unpredictability.
- The fallback to rand() has not been changed in this stable-branch since
- the necessary code changes for correct error-handling are rather intrusive.
+ unpredictable pseudo-random numbers.
If you are using D-Bus over the (unencrypted!) tcp: or nonce-tcp: transport,
in conjunction with DBUS_COOKIE_SHA1 and a shared home directory using
@@ -35,7 +62,36 @@ Security hardening:
(fd.o #90414, Simon McVittie)
-Other fixes:
+• When asked for random numbers for DBUS_COOKIE_SHA1, the nonce-tcp:
+ transport, UUIDs or any other reason, fail if we cannot obtain entropy
+ (from /dev/urandom or CryptGenRandom()) or an out-of-memory condition
+ occurs, instead of silently falling back to low-entropy pseudorandom
+ numbers from rand(). (fd.o #90414; Simon McVittie, Ralf Habacker)
+
+Enhancements:
+
+• Add dbus_message_iter_get_element_count()
+ (fd.o #30350; Christian Dywan, Simon McVittie)
+
+• Introduce new internal DBusSocket and DBusPollable types so we can
+ stop treating the Windows SOCKET type as if it was int. DBusSocket
+ is specifically a socket, cross-platform. DBusPollable is whatever
+ _dbus_poll() can act on, i.e. a fd on Unix or a SOCKET on Windows.
+ (fd.o #89444; Ralf Habacker, Simon McVittie)
+
+• All regression tests now output TAP <https://testanything.org/>
+ (fd.o #89846, Simon McVittie)
+
+• Internal APIs consistently use signed values for timestamps
+ (fd.o #18494, Peter McCurdy)
+
+• Improve diagnostics when UpdateActivationEnvironment calls are rejected
+ (fd.o #88812, Simon McVittie)
+
+• Clean up a lot of compiler warnings
+ (fd.o #17289, fd.o #89284; Ralf Habacker, Simon McVittie)
+
+Fixes:
• Add locking to DBusCounter's reference count and notify function
(fd.o #89297, Adrian Szyndela)
@@ -43,28 +99,142 @@ Other fixes:
• Ensure that DBusTransport's reference count is protected by the
corresponding DBusConnection's lock (fd.o #90312, Adrian Szyndela)
-• On Windows, listen on the same port for IPv4 and IPv6 (previously
- broken by an endianness mistake), and fix a failure to bind TCP
- sockets on approximately 1 attempt in 256 (fd.o #87999, Ralf Habacker)
-
• Correctly release DBusServer mutex before early-return if we run out
of memory while copying authentication mechanisms (fd.o #90021,
Ralf Habacker)
+• Make dbus-test-tool and dbus-update-activation-environment portable
+ to Windows (fd.o #90089, Ralf Habacker)
+
• Correctly initialize all fields of DBusTypeReader (fd.o #90021;
Ralf Habacker, Simon McVittie)
• Fix some missing \n in verbose (debug log) messages (fd.o #90004,
Ralf Habacker)
-• Clean up some memory leaks in test code (fd.o #90021, Ralf Habacker)
+• Clean up some memory and fd leaks in test code and tools
+ (fd.o #90021, Ralf Habacker)
+
+• Fix a NULL dereference if the dbus-daemon cannot read a configuration
+ directory for a reason that is not ENOENT (fd.o #90021, Ralf Habacker)
+
+• CMake generates a versioned shared library even if the revision is 0,
+ as it usually is on the development branch. (fd.o #89450, Ralf Habacker)
-D-Bus 1.8.16 (2015-02-09)
+D-Bus 1.9.14 (2015-03-02)
==
-The “poorly concealed wrestlers” release.
+The “don't stand in the poison cloud” release.
-Security fixes:
+Dependencies:
+
+• dbus-daemon and dbus-daemon-launch-helper now require libdbus. They
+ were previously linked to a static version of libdbus.
+
+• The tests no longer require dbus-glib in order to exercise the libdbus
+ shared library; they are always linked to libdbus now.
+
+Build-time configuration:
+
+• The new --enable-user-session option, off by default, can be enabled
+ by OS integrators intending to use systemd to provide a session bus
+ per user (in effect, treating all concurrent graphical and non-graphical
+ login sessions as one large session)
+
+Enhancements:
+
+• All executables are now linked dynamically to libdbus.
+ (fd.o #83115; Bertrand SIMONNET, Simon McVittie, Ralf Habacker)
+
+• On platforms that support them (GNU libc and possibly others),
+ libdbus now has versioned symbols for its public API.
+ All public symbols (visible in the header files) are currently
+ versioned as LIBDBUS_1_3; private symbols starting with _dbus or
+ dbus_internal have a version that changes with each release, and
+ must not be used by applications. (also fd.o #83115)
+
+• New listenable address mode "unix:runtime=yes" which listens on
+ a real filesystem (non-abstract) socket $XDG_RUNTIME_DIR/bus
+ (fd.o #61303; Colin Walters, Alexander Larsson, Simon McVittie)
+
+• Add optional systemd units for a per-user bus listening on
+ $XDG_RUNTIME_DIR/bus (fd.o #61301; Simon McVittie, Colin Walters)
+
+• On Unix platforms, both libdbus and "dbus-launch --autolaunch"
+ default to connecting to $XDG_RUNTIME_DIR/bus if it is a socket
+ (also fd.o #61301)
+
+• New dbus-update-activation-environment tool uploads environment
+ variables to "dbus-daemon --session" and optionally "systemd --user",
+ primarily as a way to keep the per-user bus compatible with
+ distributions' existing X11 login scripts (also fd.o #61301)
+
+• <includedir/> elements in dbus-daemon configuration are now silently
+ ignored if the directory does not exist. (fd.o #89280, Dimitri John Ledkov)
+
+• Add microsecond-resolution timestamps to the default output of
+ dbus-monitor and dbus-send (fd.o #88896; Ralf Habacker, Simon McVittie)
+
+Fixes:
+
+• Fix a race condition in the 'monitor' test introduced in 1.9.10
+ (fd.o #89222, Simon McVittie)
+
+D-Bus 1.9.12 (2015-02-19)
+==
+
+The “monster lasagna” release.
+
+Dependencies:
+
+• Ducktype and yelp-tools are now required to build complete documentation
+ (they are optional for normal builds).
+
+Enhancements:
+
+• D-Bus Specification version 0.26
+ · GetConnectionCredentials can return LinuxSecurityLabel or WindowsSID
+ · document the BecomeMonitor method
+
+• On Linux, add LinuxSecurityLabel to GetConnectionCredentials
+ (fd.o #89041; Tyler Hicks, Simon McVittie)
+
+• On Linux, add support for AppArmor mediation of message sending and
+ receiving and name ownership (paralleling existing SELinux mediation
+ support), and eavesdropping (a new check, currently AppArmor-specific)
+ (fd.o #75113; John Johansen, Tyler Hicks, Simon McVittie)
+
+• In dbus-send and dbus-monitor, pretty-print \0-terminated bytestrings
+ that have printable ASCII contents; we previously only did this for
+ unterminated bytestrings (fd.o #89109, Simon McVittie)
+
+• Add a guide to designing good D-Bus APIs (fd.o #88994, Philip Withnall)
+
+• On Windows, add WindowsSID to GetConnectionCredentials
+ (fd.o #54445, Ralf Habacker)
+
+• Improve clarity of dbus-monitor --profile output and add more columns
+ (fd.o #89165, Ralf Habacker)
+
+• Add a man page for dbus-test-tool, and build it under CMake as well
+ as Autotools (fd.o#89086, Simon McVittie)
+
+• If dbus-daemon was compiled with --enable-verbose, add a D-Bus API
+ to control it at runtime, overriding the DBUS_VERBOSE environment variable
+ (fd.o #88896, Ralf Habacker)
+
+Fixes:
+
+• Reduce the number of file descriptors used in the fd-passing test,
+ avoiding failure under the default Linux fd limit, and automatically
+ skip it if the rlimit is too small (fd.o #88998, Simon McVittie)
+
+D-Bus 1.9.10 (2015-02-09)
+==
+
+The “sad cyborgs” release.
+
+Security fixes merged from 1.8.16:
• Do not allow non-uid-0 processes to send forged ActivationFailure
messages. On Linux systems with systemd activation, this would
@@ -73,21 +243,87 @@ Security fixes:
the actual service activation and causing an error reply
to be sent back when service auto-activation was requested.
This does not prevent the real service from being started,
- so it only works while the real service is not running.
+ so the attack only works while the real service is not running.
(CVE-2015-0245, fd.o #88811; Simon McVittie)
+Enhancements:
+
+• The new Monitoring interface in the dbus-daemon lets dbus-monitor and
+ similar tools receive messages without altering the security properties
+ of the system bus, by calling the new BecomeMonitor method on a
+ private connection. This bypasses the normal <allow> and <deny> rules
+ entirely, so to preserve normal message-privacy assumptions, only root
+ is allowed to do this on the system bus. Restricted environments,
+ such as Linux with LSMs, should lock down access to the Monitoring
+ interface. (fd.o #46787, Simon McVittie)
+
+• dbus-monitor uses BecomeMonitor to capture more traffic, if the
+ dbus-daemon supports it and access permissions allow it.
+ It still supports the previous approach ("eavesdropping" match rules)
+ for compatibility with older bus daemons. (fd.o #46787, Simon)
+
+• dbus-monitor can now log the message stream as binary data for later
+ analysis, with either no extra framing beyond the normal D-Bus headers,
+ or libpcap-compatible framing treating each D-Bus message
+ as a captured packet. (fd.o #46787, Simon)
+
Other fixes:
-• fix a Windows build failure (fd.o #88009, Ralf Habacker)
+• Fix some CMake build regressions (fd.o #88964, Ralf Habacker)
+
+• On Unix, forcibly terminate regression tests after 60 seconds to
+ prevent them from blocking continuous integration frameworks
+ (fd.o #46787, Simon)
+
+D-Bus 1.9.8 (2015-02-03)
+==
+
+The “all the types of precipitation” release.
+
+Dependencies:
+
+• full test coverage now requires GLib 2.36
+• full test coverage now requires PyGI (PyGObject 3,
+ "import gi.repository.GObject") instead of the
+ obsolete PyGObject 2 ("import gobject")
+
+Enhancements:
+
+• add GLib-style "installed tests" (fd.o #88810, Simon McVittie)
+
+• better regression test coverage, including systemd activation
+ (fd.o #57952, #88810; Simon McVittie)
+
+Fixes:
+
+• fatal errors correctly make the dbus-daemon exit even if <syslog/> is
+ turned off (fd.o #88808, Simon McVittie)
+
+• TCP sockets on Windows no longer fail to listen approximately 1 time
+ in 256, caused by a logic error that should have always made it fail but
+ was mitigated by incorrect endianness for the port number
+ (fd.o #87999, Ralf Habacker)
+
+• fix some Windows build failures (fd.o #88009, #88010; Ralf Habacker)
• on Windows, allow up to 8K connections to the dbus-daemon instead of the
previous 64, completing a previous fix which only worked under
Autotools (fd.o #71297, Ralf Habacker)
-D-Bus 1.8.14 (2015-01-05)
+• on Windows, if the IP family is unspecified only use IPv4,
+ to mitigate IPv6 not working correctly (fd.o #87999, Ralf Habacker)
+
+• fix some unlikely memory leaks on OOM (fd.o #88087, Simon McVittie)
+
+• lcov code coverage analysis works again (fd.o #88808, Simon McVittie)
+
+• fix an unused function error with --disable-embedded-tests (fd.o #87837,
+ Thiago Macieira)
+
+D-Bus 1.9.6 (2015-01-05)
==
-The “40lb of roofing nails” release.
+The “I do have a bread knife” release.
Security hardening:
@@ -115,10 +351,10 @@ Other fixes:
• Add missing initialization so GetExtendedTcpTable doesn't crash on
Windows Vista SP0 (fd.o #77008, Илья А. Ткаченко)
-D-Bus 1.8.12 (2014-11-24)
+D-Bus 1.9.4 (2014-11-24)
==
-The “days of fuchsia passed” release.
+The “extra-sturdy caramel” release.
Fixes:
@@ -144,10 +380,10 @@ Fixes:
to receive a message (and in builds with assertions enabled, don't
assert under the same conditions). (fd.o #86194, Jacek Bukarewicz)
-D-Bus 1.8.10 (2014-11-10)
+D-Bus 1.9.2 (2014-11-10)
==
-The “tenants with a leaking roof get priority” release.
+The “structurally unsound flapjack” release.
Security fixes:
@@ -156,6 +392,155 @@ Security fixes:
file descriptors, completing the incomplete fix in 1.8.8.
(CVE-2014-7824, fd.o #85105; Simon McVittie, Alban Crequy)
+Enhancements:
+
+• D-Bus Specification version 0.25
+ · new value 'const' for EmitsChangedSignal annotation
+ (fd.o #72958, Lennart Poettering)
+ · new ALLOW_INTERACTIVE_AUTHORIZATION flag, for PolicyKit and similar
+ (fd.o #83449; Lennart Poettering, Simon McVittie)
+ · annotate table of types with reserved/basic/container, and for
+ basic types, fixed/string-like
+ · clarify arbitrary limits by quoting them in mebibytes
+
+• New API: add accessors for the ALLOW_INTERACTIVE_AUTHORIZATION flag
+ (fd.o #83449, Simon McVittie)
+
+• Add dbus-test-tool, a D-Bus swiss army knife with multiple subcommands,
+ useful for debugging and performance testing:
+ · dbus-test-tool spam: send repeated messages
+ · dbus-test-tool echo: send an empty reply for all method calls
+ · dbus-test-tool black-hole: do not reply to method calls
+ (fd.o #34140; Alban Crequy, Simon McVittie, Will Thompson)
+
+• Add support for process ID in credentials-passing on NetBSD
+ (fd.o #69702, Patrick Welche)
+
+• Add an example script to find potentially undesired match rules
+ (fd.o #84598, Alban Crequy)
+
+• Document the central assumption that makes our use of credentials-passing
+ secure (fd.o #83499, Simon McVittie)
+
+• Replace the dbus-glib section of the tutorial with a GDBus recommendation,
+ and add some links to GDBus and QtDBus documentation (fd.o #25140,
+ Simon McVittie)
+
+Fixes:
+
+• Use a less confusing NoReply message when disconnected with a reply pending
+ (fd.o #76112, Simon McVittie)
+
+• Make the .pc file relocatable by letting pkg-config do all variable
+ expansion itself (fd.o #75858, Руслан Ижбулатов)
+
+• Fix a build failure on platforms with kqueue, which regressed in 1.9.0
+ (fd.o #85563, Patrick Welche)
+
+• Consistently save errno after socket calls (fd.o #83625, Simon McVittie)
+
+• In dbus-spawn, when the grandchild process exits due to a failed exec(),
+ do not lose the exec() errno (fd.o #24821, Simon McVittie)
+
+• Do not fail the tests if a parent process has leaked non-close-on-exec
+ file descriptors to us (fd.o #73689, fd.o #83899; Simon McVittie)
+
+• Do not fail the tests on Unix platforms with incomplete
+ credentials-passing support, but do fail if we can't pass credentials
+ on a platform where it is known to work: Linux, FreeBSD, OpenBSD, NetBSD
+ (fd.o #69702, Simon McVittie)
+
+• Detect accept4, dirfd, inotify_init1, pipe2, and Unix fd passing
+ when building with cmake, and expand test coverage there
+ (fd.o #73689; Ralf Habacker, Simon McVittie)
+
+D-Bus 1.9.0 (2014-10-01)
+==
+
+The “tiered cheeses” release.
+
+Requirements:
+
+• Support for the systemd: (LISTEN_FDS) pseudo-transport on Linux now
+ requires either the libsystemd or libsd-daemon shared library, dropping the
+ embedded convenience copy of sd-daemon (fd.o #71818, Simon)
+
+Build-time configuration changes:
+
+• The Stats interface is now enabled by default, and locked-down to
+ root-only on the system bus. Configure with --disable-stats
+ to disable it altogether on memory- or disk-constrained systems,
+ or see ${docdir}/examples/ to open it up to non-root users on the
+ system bus or restrict access on the session bus.
+ (fd.o #80759; Simon McVittie, Alban Crequy)
+
+• The CMake build system now builds the same shared library name as Autotools
+ on at least Linux and Windows:
+ - on Linux (and perhaps other Unix platforms), it previously built
+ libdbus-1.so, but now builds libdbus-1.so.3.* with development
+ symlink libdbus-1.so and SONAME/symlink libdbus-1.so.3
+ - on Windows, it previously built either libdbus-1.dll (release) or
+ libdbus-1d.dll (debug), but now builds libdbus-1-3.dll, copied to
+ libdbus-1.dll for compatibility with older applications.
+ (fd.o #74117, Ralf Habacker)
+
+Enhancements:
+
+• D-Bus Specification version 0.24
+ · document how to quote match rules (fd.o #24307, Simon McVittie)
+ · explicitly say that most message types never expect a reply
+ regardles of whether they have NO_REPLY_EXPECTED
+ (fd.o #75749, Simon McVittie)
+
+• on Unix platforms, disable Nagle's algorithm on TCP connections to improve
+ initial latency (fd.o #75544, Matt Hoosier)
+
+• use backtrace() if it is in -lexecinfo instead of libc, as on NetBSD
+ (fd.o #69702, Patrick Welche)
+
+• in dbus-monitor, print more information about file descriptors
+ (fd.o #80603, Alban Crequy)
+
+• do not install system bus configuration if built for Windows
+ (fd.o #83583; Ralf Habacker, Simon McVittie)
+
+• Add GetAllMatchRules to the Stats interface (fd.o #24307, Alban Crequy)
+
+• Add a regression test for file descriptor passing (fd.o #83622,
+ Simon McVittie)
+
+Fixes:
+
+• fix an incorrect error message if a Unix socket path is too long
+ (fd.o #73887, Antoine Jacoutot)
+
+• in an MSYS/Cygwin environment, pass Unix-style filenames to xmlto,
+ fixing documentation generation (fd.o #75860, Руслан Ижбулатов)
+
+• in Unix with X11, avoid giving dbus-launch a misleading argv[0]
+ in ps(1) (fd.o #69716, Chengwei Yang)
+
+• avoid calling poll() with timeout < -1, which is considered invalid
+ on FreeBSD and NetBSD (fd.o #78480, Jaap Boender)
+
+• be portable to BSD-derived platforms where O_CLOEXEC is unavailable in libc
+ (like Mac OS X 10.6), or available in libc but unsupported by the kernel
+ (fd.o #77032; rmvsxop, OBATA Akio, Patrick Welche)
+
+• Fix include path for test/internal/*.c with cmake (Ralf Habacker)
+
+• Documentation improvements
+ (fd.o #80795, #84313; Thomas Haller, Sebastian Rasmussen)
+
+• in dbus-monitor, do not leak file descriptors that we have monitored
+ (fd.o #80603, Alban Crequy)
+
+• Set the close-on-exec flag for the inotify file descriptor, even
+ if built with CMake or older libc (fd.o #73689, Simon McVittie)
+
+• Remove some LGPL code from the Windows dbus-daemon
+ (fd.o #57272, Ralf Habacker)
+
D-Bus 1.8.8 (2014-09-16)
==
diff --git a/bus/.gitignore b/bus/.gitignore
index d856369b..37b04778 100644
--- a/bus/.gitignore
+++ b/bus/.gitignore
@@ -24,3 +24,5 @@ test-bus-system
dbus.service
dbus.socket
org.freedesktop.dbus-session.plist
+example-session-disable-stats.conf
+example-system-enable-stats.conf
diff --git a/bus/Makefile.am b/bus/Makefile.am
index f335e30c..38c0558f 100644
--- a/bus/Makefile.am
+++ b/bus/Makefile.am
@@ -1,9 +1,11 @@
-configdir=$(sysconfdir)/dbus-1
+dbusdatadir=$(datadir)/dbus-1
+legacydbusdatadir=$(sysconfdir)/dbus-1
dbus_daemon_execdir = $(DBUS_DAEMONDIR)
DBUS_BUS_LIBS = \
$(XML_LIBS) \
$(SELINUX_LIBS) \
+ $(APPARMOR_LIBS) \
$(THREAD_LIBS) \
$(ADT_LIBS) \
$(NETWORK_libs) \
@@ -17,10 +19,11 @@ DBUS_LAUNCHER_LIBS = \
AM_CPPFLAGS = \
-I$(top_srcdir) \
+ $(DBUS_STATIC_BUILD_CPPFLAGS) \
$(XML_CFLAGS) \
- -DDBUS_SYSTEM_CONFIG_FILE=\""$(configdir)/system.conf"\" \
+ $(APPARMOR_CFLAGS) \
+ -DDBUS_SYSTEM_CONFIG_FILE=\""$(dbusdatadir)/system.conf"\" \
-DDBUS_COMPILATION \
- -DDBUS_STATIC_BUILD \
$(NULL)
# if assertions are enabled, improve backtraces
@@ -31,11 +34,26 @@ EFENCE=
CONFIG_IN_FILES= \
session.conf.in \
system.conf.in \
- org.freedesktop.dbus-session.plist.in
+ legacy-config/session.conf.in \
+ legacy-config/system.conf.in \
+ org.freedesktop.dbus-session.plist.in \
+ example-system-enable-stats.conf.in \
+ example-session-disable-stats.conf.in \
+ $(NULL)
+
+dbusdata_DATA = session.conf
+legacydbusdata_DATA = legacy-config/session.conf
+
+if DBUS_UNIX
+dbusdata_DATA += system.conf
+legacydbusdata_DATA += legacy-config/system.conf
+endif
-config_DATA= \
- session.conf \
- system.conf
+examplesdir = ${docdir}/examples
+examples_DATA = \
+ example-system-enable-stats.conf \
+ example-session-disable-stats.conf \
+ $(NULL)
if DBUS_ENABLE_LAUNCHD
agentdir=$(LAUNCHD_AGENT_DIR)
@@ -58,6 +76,8 @@ BUS_SOURCES= \
activation.c \
activation.h \
activation-exit-codes.h \
+ apparmor.c \
+ apparmor.h \
bus.c \
bus.h \
config-parser.c \
@@ -97,6 +117,7 @@ dbus_daemon_SOURCES= \
main.c
dbus_daemon_LDADD= \
+ $(top_builddir)/dbus/libdbus-1.la \
$(top_builddir)/dbus/libdbus-internal.la \
$(EFENCE) \
$(DBUS_BUS_LIBS)
@@ -121,7 +142,8 @@ dbus_daemon_launch_helper_SOURCES= \
$(LAUNCH_HELPER_SOURCES)
dbus_daemon_launch_helper_LDADD= \
- $(top_builddir)/dbus/libdbus-internal.la \
+ $(top_builddir)/dbus/libdbus-1.la \
+ $(top_builddir)/dbus/libdbus-internal.la \
$(DBUS_LAUNCHER_LIBS)
## we build another binary so we can do the launch testing without root privs.
@@ -131,6 +153,7 @@ dbus_daemon_launch_helper_test_SOURCES= \
$(LAUNCH_HELPER_SOURCES)
dbus_daemon_launch_helper_test_LDADD= \
+ $(top_builddir)/dbus/libdbus-1.la \
$(top_builddir)/dbus/libdbus-internal.la \
$(DBUS_LAUNCHER_LIBS)
@@ -145,8 +168,10 @@ test_bus_launch_helper_SOURCES= \
$(LAUNCH_HELPER_SOURCES)
test_bus_launch_helper_LDADD= \
+ $(top_builddir)/dbus/libdbus-1.la \
$(top_builddir)/dbus/libdbus-internal.la \
$(DBUS_LAUNCHER_LIBS)
+ $(NULL)
test_bus_launch_helper_CPPFLAGS = \
$(AM_CPPFLAGS) \
@@ -169,11 +194,11 @@ if DBUS_ENABLE_EMBEDDED_TESTS
## even when not doing "make check"
# run as a test by test/Makefile.am
-noinst_PROGRAMS += test-bus test-bus-system
+noinst_PROGRAMS += test-bus
if DBUS_UNIX
# run as a test by test/Makefile.am
-noinst_PROGRAMS += test-bus-launch-helper
+noinst_PROGRAMS += test-bus-launch-helper test-bus-system
# this is used by the tests but is not,itself, a test
noinst_PROGRAMS += dbus-daemon-launch-helper-test
endif DBUS_UNIX
@@ -190,24 +215,34 @@ test_bus_system_SOURCES= \
utils.h \
test-system.c
-test_bus_system_LDADD=$(top_builddir)/dbus/libdbus-internal.la $(DBUS_BUS_LIBS)
+test_bus_system_LDADD = \
+ $(top_builddir)/dbus/libdbus-1.la \
+ $(top_builddir)/dbus/libdbus-internal.la \
+ $(DBUS_BUS_LIBS) \
+ $(NULL)
test_bus_SOURCES= \
$(BUS_SOURCES) \
test-main.c
-test_bus_LDADD=$(top_builddir)/dbus/libdbus-internal.la $(DBUS_BUS_LIBS)
+test_bus_LDADD = \
+ $(top_builddir)/dbus/libdbus-1.la \
+ $(top_builddir)/dbus/libdbus-internal.la \
+ $(DBUS_BUS_LIBS) \
+ $(NULL)
## mop up the gcov files
clean-local:
/bin/rm *.bb *.bbg *.da *.gcov || true
install-data-hook:
+ $(mkinstalldirs) $(DESTDIR)$(dbusdatadir)/session.d
+ $(mkinstalldirs) $(DESTDIR)$(dbusdatadir)/services
+if DBUS_UNIX
$(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)$(dbusdatadir)/system.d
+ $(mkinstalldirs) $(DESTDIR)$(dbusdatadir)/system-services
+endif
if HAVE_SYSTEMD
# Install dbus.socket as default implementation of a D-Bus stack.
# Deliberately not using $(LN_S) here: ln -fs is not universally portable,
@@ -220,6 +255,10 @@ if HAVE_SYSTEMD
$(mkinstalldirs) $(DESTDIR)$(systemdsystemunitdir)/multi-user.target.wants
ln -fs ../dbus.service $(DESTDIR)$(systemdsystemunitdir)/multi-user.target.wants/dbus.service
endif
+if DBUS_ENABLE_USER_SESSION
+ $(mkinstalldirs) $(DESTDIR)$(systemduserunitdir)/sockets.target.wants
+ ln -fs ../dbus.socket $(DESTDIR)$(systemduserunitdir)/sockets.target.wants/dbus.socket
+endif
if DBUS_UNIX
install-exec-hook:
@@ -271,13 +310,23 @@ endif
if HAVE_SYSTEMD
SCRIPT_IN_FILES += \
dbus.service.in \
- dbus.socket.in
+ dbus.socket.in \
+ systemd-user/dbus.service.in \
+ systemd-user/dbus.socket.in \
+ $(NULL)
systemdsystemunit_DATA = \
dbus.service \
dbus.socket
endif
+if DBUS_ENABLE_USER_SESSION
+systemduserunit_DATA = \
+ systemd-user/dbus.service \
+ systemd-user/dbus.socket \
+ $(NULL)
+endif
+
#### Extra dist
EXTRA_DIST=$(CONFIG_IN_FILES) $(SCRIPT_IN_FILES)
diff --git a/bus/activation.c b/bus/activation.c
index ecd19bb4..679a40eb 100644
--- a/bus/activation.c
+++ b/bus/activation.c
@@ -637,7 +637,7 @@ update_directory (BusActivation *activation,
if (!_dbus_string_ends_with_c_str (&filename, ".service"))
{
- _dbus_verbose ("Skipping non-.service file %s\n",
+ _dbus_verbose ("Skipping non-.service file '%s'\n",
_dbus_string_get_const_data (&filename));
continue;
}
@@ -1044,7 +1044,7 @@ restore_pending (void *data)
}
static void
-free_pending_restore_data (void *data)
+free_restore_pending_data (void *data)
{
RestorePendingData *d = data;
@@ -1074,9 +1074,9 @@ add_restore_pending_to_transaction (BusTransaction *transaction,
if (d->hash_entry == NULL ||
!bus_transaction_add_cancel_hook (transaction, restore_pending, d,
- free_pending_restore_data))
+ free_restore_pending_data))
{
- free_pending_restore_data (d);
+ free_restore_pending_data (d);
return FALSE;
}
@@ -1478,11 +1478,8 @@ pending_activation_timed_out (void *data)
dbus_error_init (&error);
- dbus_set_error (&error, DBUS_ERROR_TIMED_OUT,
- "Activation of %s timed out",
- pending_activation->service_name);
- bus_context_log (pending_activation->activation->context,
- DBUS_SYSTEM_LOG_INFO,
+ bus_context_log_and_set_error (pending_activation->activation->context,
+ DBUS_SYSTEM_LOG_INFO, &error, DBUS_ERROR_TIMED_OUT,
"Failed to activate service '%s': timed out",
pending_activation->service_name);
@@ -1704,7 +1701,7 @@ child_setup (void *user_data)
{
/* unfortunately we don't actually know the service name here */
bus_context_log (activation->context,
- DBUS_SYSTEM_LOG_INFO,
+ DBUS_SYSTEM_LOG_WARNING,
"Failed to reset fd limit before activating "
"service: %s: %s",
error.name, error.message);
@@ -2007,6 +2004,17 @@ bus_activation_activate_service (BusActivation *activation,
_dbus_string_init_const (&service_string, "org.freedesktop.systemd1");
service = bus_registry_lookup (registry, &service_string);
+ /* Following the general principle of "log early and often",
+ * we capture that we *want* to send the activation message, even if
+ * systemd is not actually there to receive it yet */
+ if (!bus_transaction_capture (activation_transaction,
+ NULL, message))
+ {
+ dbus_message_unref (message);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
if (service != NULL)
{
bus_context_log (activation->context,
@@ -2389,6 +2397,7 @@ test_remove_directory (DBusString *dir)
if (!test_remove_service_file (dir, _dbus_string_get_const_data (&filename)))
{
ret_val = FALSE;
+ _dbus_directory_close (iter);
goto out;
}
}
@@ -2599,7 +2608,7 @@ bus_activation_service_reload_test (const DBusString *test_data_dir)
return FALSE;
if (!_dbus_string_append (&directory, "/dbus-reload-test-") ||
- !_dbus_generate_random_ascii (&directory, 6))
+ !_dbus_generate_random_ascii (&directory, 6, NULL))
{
return FALSE;
}
diff --git a/bus/apparmor.c b/bus/apparmor.c
new file mode 100644
index 00000000..a1b3621a
--- /dev/null
+++ b/bus/apparmor.c
@@ -0,0 +1,1128 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ * apparmor.c AppArmor security checks for D-Bus
+ *
+ * Based on selinux.c
+ *
+ * Copyright © 2014-2015 Canonical, Ltd.
+ *
+ * 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.h>
+#include "apparmor.h"
+
+#ifdef HAVE_APPARMOR
+
+#include <dbus/dbus-internals.h>
+#include <dbus/dbus-string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/apparmor.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#ifdef HAVE_LIBAUDIT
+#include <cap-ng.h>
+#include <libaudit.h>
+#endif /* HAVE_LIBAUDIT */
+
+#include "connection.h"
+#include "utils.h"
+
+/* Store the value telling us if AppArmor D-Bus mediation is enabled. */
+static dbus_bool_t apparmor_enabled = FALSE;
+
+typedef enum {
+ APPARMOR_DISABLED,
+ APPARMOR_ENABLED,
+ APPARMOR_REQUIRED
+} AppArmorConfigMode;
+
+/* Store the value of the AppArmor mediation mode in the bus configuration */
+static AppArmorConfigMode apparmor_config_mode = APPARMOR_ENABLED;
+
+#ifdef HAVE_LIBAUDIT
+static int audit_fd = -1;
+#endif
+
+/* The AppArmor context, consisting of a label and a mode. */
+struct BusAppArmorConfinement
+{
+ int refcount; /* Reference count */
+
+ char *label; /* AppArmor confinement label */
+ const char *mode; /* AppArmor confinement mode (freed by freeing *label) */
+};
+
+static BusAppArmorConfinement *bus_con = NULL;
+
+/**
+ * Callers of this function give up ownership of the *label and *mode
+ * pointers.
+ *
+ * Additionally, the responsibility of freeing *label and *mode becomes the
+ * responsibility of the bus_apparmor_confinement_unref() function. However, it
+ * does not free *mode because libapparmor's aa_getcon(), and libapparmor's
+ * other related functions, allocate a single buffer for *label and *mode and
+ * then separate the two char arrays with a NUL char. See the aa_getcon(2) man
+ * page for more details.
+ */
+static BusAppArmorConfinement*
+bus_apparmor_confinement_new (char *label,
+ const char *mode)
+{
+ BusAppArmorConfinement *confinement;
+
+ confinement = dbus_new0 (BusAppArmorConfinement, 1);
+ if (confinement != NULL)
+ {
+ confinement->refcount = 1;
+ confinement->label = label;
+ confinement->mode = mode;
+ }
+
+ return confinement;
+}
+
+void
+bus_apparmor_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 */
+}
+
+/*
+ * Return TRUE on successful check, FALSE on OOM.
+ * Set *is_supported to whether AA has D-Bus features.
+ */
+static dbus_bool_t
+_bus_apparmor_detect_aa_dbus_support (dbus_bool_t *is_supported)
+{
+ int mask_file;
+ DBusString aa_dbus;
+ char *aa_securityfs = NULL;
+ dbus_bool_t retval = FALSE;
+
+ *is_supported = FALSE;
+
+ if (!_dbus_string_init (&aa_dbus))
+ return FALSE;
+
+ if (aa_find_mountpoint (&aa_securityfs) != 0)
+ goto out;
+
+ /*
+ * John Johansen has confirmed that the mainline kernel will not have
+ * the apparmorfs/features/dbus/mask file until the mainline kernel
+ * has AppArmor getpeersec support.
+ */
+ if (!_dbus_string_append (&aa_dbus, aa_securityfs) ||
+ !_dbus_string_append (&aa_dbus, "/features/dbus/mask"))
+ goto out;
+
+ /* We need to open() the flag file, not just stat() it, because AppArmor
+ * does not mediate stat() in the apparmorfs. If you have a
+ * dbus-daemon inside an LXC container, with insufficiently broad
+ * AppArmor privileges to do its own AppArmor mediation, the desired
+ * result is that it behaves as if AppArmor was not present; but a stat()
+ * here would succeed, and result in it trying and failing to do full
+ * mediation. https://bugs.launchpad.net/ubuntu/+source/dbus/+bug/1238267 */
+ mask_file = open (_dbus_string_get_const_data (&aa_dbus),
+ O_RDONLY | O_CLOEXEC);
+ if (mask_file != -1)
+ {
+ *is_supported = TRUE;
+ close (mask_file);
+ }
+
+ retval = TRUE;
+
+out:
+ free (aa_securityfs);
+ _dbus_string_free (&aa_dbus);
+
+ return retval;
+}
+
+static dbus_bool_t
+modestr_is_complain (const char *mode)
+{
+ if (mode && strcmp (mode, "complain") == 0)
+ return TRUE;
+ return FALSE;
+}
+
+static void
+log_message (dbus_bool_t allow, const char *op, DBusString *data)
+{
+ const char *mstr;
+
+ if (allow)
+ mstr = "ALLOWED";
+ else
+ mstr = "DENIED";
+
+#ifdef HAVE_LIBAUDIT
+ if (audit_fd >= 0)
+ {
+ DBusString avc;
+
+ capng_get_caps_process ();
+ if (!capng_have_capability (CAPNG_EFFECTIVE, CAP_AUDIT_WRITE))
+ goto syslog;
+
+ if (!_dbus_string_init (&avc))
+ goto syslog;
+
+ if (!_dbus_string_append_printf (&avc,
+ "apparmor=\"%s\" operation=\"dbus_%s\" %s\n",
+ mstr, op, _dbus_string_get_const_data (data)))
+ {
+ _dbus_string_free (&avc);
+ goto syslog;
+ }
+
+ /* FIXME: need to change this to show real user */
+ audit_log_user_avc_message (audit_fd, AUDIT_USER_AVC,
+ _dbus_string_get_const_data (&avc),
+ NULL, NULL, NULL, getuid ());
+ _dbus_string_free (&avc);
+ return;
+ }
+
+syslog:
+#endif /* HAVE_LIBAUDIT */
+
+ syslog (LOG_USER | LOG_NOTICE, "apparmor=\"%s\" operation=\"dbus_%s\" %s\n",
+ mstr, op, _dbus_string_get_const_data (data));
+}
+
+static dbus_bool_t
+_dbus_append_pair_uint (DBusString *auxdata, const char *name,
+ unsigned long value)
+{
+ return _dbus_string_append (auxdata, " ") &&
+ _dbus_string_append (auxdata, name) &&
+ _dbus_string_append (auxdata, "=") &&
+ _dbus_string_append_uint (auxdata, value);
+}
+
+static dbus_bool_t
+_dbus_append_pair_str (DBusString *auxdata, const char *name, const char *value)
+{
+ return _dbus_string_append (auxdata, " ") &&
+ _dbus_string_append (auxdata, name) &&
+ _dbus_string_append (auxdata, "=\"") &&
+ _dbus_string_append (auxdata, value) &&
+ _dbus_string_append (auxdata, "\"");
+}
+
+static dbus_bool_t
+_dbus_append_mask (DBusString *auxdata, uint32_t mask)
+{
+ const char *mask_str;
+
+ /* Only one permission bit can be set */
+ if (mask == AA_DBUS_SEND)
+ mask_str = "send";
+ else if (mask == AA_DBUS_RECEIVE)
+ mask_str = "receive";
+ else if (mask == AA_DBUS_BIND)
+ mask_str = "bind";
+ else
+ return FALSE;
+
+ return _dbus_append_pair_str (auxdata, "mask", mask_str);
+}
+
+static dbus_bool_t
+is_unconfined (const char *con, const char *mode)
+{
+ /* treat con == NULL as confined as it is going to result in a denial */
+ if ((!mode && con && strcmp (con, "unconfined") == 0) ||
+ strcmp (mode, "unconfined") == 0)
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static dbus_bool_t
+query_append (DBusString *query, const char *buffer)
+{
+ if (!_dbus_string_append_byte (query, '\0'))
+ return FALSE;
+
+ if (buffer && !_dbus_string_append (query, buffer))
+ return FALSE;
+
+ return TRUE;
+}
+
+static dbus_bool_t
+build_common_query (DBusString *query, const char *con, const char *bustype)
+{
+ /**
+ * libapparmor's aa_query_label() function scribbles over the first
+ * AA_QUERY_CMD_LABEL_SIZE bytes of the query string with a private value.
+ */
+ return _dbus_string_insert_bytes (query, 0, AA_QUERY_CMD_LABEL_SIZE, 0) &&
+ _dbus_string_append (query, con) &&
+ _dbus_string_append_byte (query, '\0') &&
+ _dbus_string_append_byte (query, AA_CLASS_DBUS) &&
+ _dbus_string_append (query, bustype ? bustype : "");
+}
+
+static dbus_bool_t
+build_service_query (DBusString *query,
+ const char *con,
+ const char *bustype,
+ const char *name)
+{
+ return build_common_query (query, con, bustype) &&
+ query_append (query, name);
+}
+
+static dbus_bool_t
+build_message_query (DBusString *query,
+ const char *src_con,
+ const char *bustype,
+ const char *name,
+ const char *dst_con,
+ const char *path,
+ const char *interface,
+ const char *member)
+{
+ return build_common_query (query, src_con, bustype) &&
+ query_append (query, name) &&
+ query_append (query, dst_con) &&
+ query_append (query, path) &&
+ query_append (query, interface) &&
+ query_append (query, member);
+}
+
+static dbus_bool_t
+build_eavesdrop_query (DBusString *query, const char *con, const char *bustype)
+{
+ return build_common_query (query, con, bustype);
+}
+
+static void
+set_error_from_query_errno (DBusError *error, int error_number)
+{
+ dbus_set_error (error, _dbus_error_from_errno (error_number),
+ "Failed to query AppArmor policy: %s",
+ _dbus_strerror (error_number));
+}
+
+static void
+set_error_from_denied_message (DBusError *error,
+ DBusConnection *sender,
+ DBusConnection *proposed_recipient,
+ dbus_bool_t requested_reply,
+ const char *msgtype,
+ const char *path,
+ const char *interface,
+ const char *member,
+ const char *error_name,
+ const char *destination)
+{
+ const char *proposed_recipient_loginfo;
+ const char *unset = "(unset)";
+
+ proposed_recipient_loginfo = proposed_recipient ?
+ bus_connection_get_loginfo (proposed_recipient) :
+ "bus";
+
+ dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+ "An AppArmor policy prevents this sender from sending this "
+ "message to this recipient; type=\"%s\", "
+ "sender=\"%s\" (%s) interface=\"%s\" member=\"%s\" "
+ "error name=\"%s\" requested_reply=\"%d\" "
+ "destination=\"%s\" (%s)",
+ msgtype,
+ bus_connection_get_name (sender),
+ bus_connection_get_loginfo (sender),
+ interface ? interface : unset,
+ member ? member : unset,
+ error_name ? error_name : unset,
+ requested_reply,
+ destination,
+ proposed_recipient_loginfo);
+}
+#endif /* HAVE_APPARMOR */
+
+/**
+ * Do early initialization; determine whether AppArmor is enabled.
+ * Return TRUE on successful check (whether AppArmor is actually
+ * enabled or not) or FALSE on OOM.
+ */
+dbus_bool_t
+bus_apparmor_pre_init (void)
+{
+#ifdef HAVE_APPARMOR
+ apparmor_enabled = FALSE;
+
+ if (!aa_is_enabled ())
+ return TRUE;
+
+ if (!_bus_apparmor_detect_aa_dbus_support (&apparmor_enabled))
+ return FALSE;
+#endif
+
+ return TRUE;
+}
+
+dbus_bool_t
+bus_apparmor_set_mode_from_config (const char *mode, DBusError *error)
+{
+#ifdef HAVE_APPARMOR
+ if (mode != NULL)
+ {
+ if (strcmp (mode, "disabled") == 0)
+ apparmor_config_mode = APPARMOR_DISABLED;
+ else if (strcmp (mode, "enabled") == 0)
+ apparmor_config_mode = APPARMOR_ENABLED;
+ else if (strcmp (mode, "required") == 0)
+ apparmor_config_mode = APPARMOR_REQUIRED;
+ else
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Mode attribute on <apparmor> must have value "
+ "\"required\", \"enabled\" or \"disabled\", "
+ "not \"%s\"", mode);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+#else
+ if (mode == NULL || strcmp (mode, "disabled") == 0 ||
+ strcmp (mode, "enabled") == 0)
+ return TRUE;
+
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Mode attribute on <apparmor> must have value \"enabled\" or "
+ "\"disabled\" but cannot be \"%s\" when D-Bus is built "
+ "without AppArmor support", mode);
+ return FALSE;
+#endif
+}
+
+/**
+ * Verify that the config mode is compatible with the kernel's AppArmor
+ * support. If AppArmor mediation will be enabled, determine the bus
+ * confinement label.
+ */
+dbus_bool_t
+bus_apparmor_full_init (DBusError *error)
+{
+#ifdef HAVE_APPARMOR
+ char *label, *mode;
+
+ if (apparmor_enabled)
+ {
+ if (apparmor_config_mode == APPARMOR_DISABLED)
+ {
+ apparmor_enabled = FALSE;
+ return TRUE;
+ }
+
+ if (bus_con == NULL)
+ {
+ if (aa_getcon (&label, &mode) == -1)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Error getting AppArmor context of bus: %s",
+ _dbus_strerror (errno));
+ return FALSE;
+ }
+
+ bus_con = bus_apparmor_confinement_new (label, mode);
+ if (bus_con == NULL)
+ {
+ BUS_SET_OOM (error);
+ free (label);
+ return FALSE;
+ }
+ }
+ }
+ else
+ {
+ if (apparmor_config_mode == APPARMOR_REQUIRED)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "AppArmor mediation required but not present");
+ return FALSE;
+ }
+ else if (apparmor_config_mode == APPARMOR_ENABLED)
+ {
+ return TRUE;
+ }
+ }
+#endif
+
+ return TRUE;
+}
+
+void
+bus_apparmor_shutdown (void)
+{
+#ifdef HAVE_APPARMOR
+ if (!apparmor_enabled)
+ return;
+
+ _dbus_verbose ("AppArmor shutdown\n");
+
+ bus_apparmor_confinement_unref (bus_con);
+ bus_con = NULL;
+
+#ifdef HAVE_LIBAUDIT
+ audit_close (audit_fd);
+#endif /* HAVE_LIBAUDIT */
+
+#endif /* HAVE_APPARMOR */
+}
+
+dbus_bool_t
+bus_apparmor_enabled (void)
+{
+#ifdef HAVE_APPARMOR
+ return apparmor_enabled;
+#else
+ return FALSE;
+#endif
+}
+
+void
+bus_apparmor_confinement_unref (BusAppArmorConfinement *confinement)
+{
+#ifdef HAVE_APPARMOR
+ if (!apparmor_enabled)
+ return;
+
+ _dbus_assert (confinement != NULL);
+ _dbus_assert (confinement->refcount > 0);
+
+ confinement->refcount -= 1;
+
+ if (confinement->refcount == 0)
+ {
+ /**
+ * Do not free confinement->mode, as libapparmor does a single malloc for
+ * both confinement->label and confinement->mode.
+ */
+ free (confinement->label);
+ dbus_free (confinement);
+ }
+#endif
+}
+
+void
+bus_apparmor_confinement_ref (BusAppArmorConfinement *confinement)
+{
+#ifdef HAVE_APPARMOR
+ if (!apparmor_enabled)
+ return;
+
+ _dbus_assert (confinement != NULL);
+ _dbus_assert (confinement->refcount > 0);
+
+ confinement->refcount += 1;
+#endif /* HAVE_APPARMOR */
+}
+
+BusAppArmorConfinement*
+bus_apparmor_init_connection_confinement (DBusConnection *connection,
+ DBusError *error)
+{
+#ifdef HAVE_APPARMOR
+ BusAppArmorConfinement *confinement;
+ char *label, *mode;
+ int fd;
+
+ if (!apparmor_enabled)
+ return NULL;
+
+ _dbus_assert (connection != NULL);
+
+ if (!dbus_connection_get_socket (connection, &fd))
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Failed to get socket file descriptor of connection");
+ return NULL;
+ }
+
+ if (aa_getpeercon (fd, &label, &mode) == -1)
+ {
+ if (errno == ENOMEM)
+ BUS_SET_OOM (error);
+ else
+ dbus_set_error (error, _dbus_error_from_errno (errno),
+ "Failed to get AppArmor confinement information of socket peer: %s",
+ _dbus_strerror (errno));
+ return NULL;
+ }
+
+ confinement = bus_apparmor_confinement_new (label, mode);
+ if (confinement == NULL)
+ {
+ BUS_SET_OOM (error);
+ free (label);
+ return NULL;
+ }
+
+ return confinement;
+#else
+ return NULL;
+#endif /* HAVE_APPARMOR */
+}
+
+/**
+ * Returns true if the given connection can acquire a service,
+ * using the tasks security context
+ *
+ * @param connection connection that wants to own the service
+ * @param bustype name of the bus
+ * @param service_name the name of the service to acquire
+ * @param error the reason for failure when FALSE is returned
+ * @returns TRUE if acquire is permitted
+ */
+dbus_bool_t
+bus_apparmor_allows_acquire_service (DBusConnection *connection,
+ const char *bustype,
+ const char *service_name,
+ DBusError *error)
+{
+
+#ifdef HAVE_APPARMOR
+ BusAppArmorConfinement *con = NULL;
+ DBusString qstr, auxdata;
+ dbus_bool_t free_auxdata = FALSE;
+ dbus_bool_t allow = FALSE, audit = TRUE;
+ unsigned long pid;
+ int res, serrno = 0;
+
+ if (!apparmor_enabled)
+ return TRUE;
+
+ _dbus_assert (connection != NULL);
+
+ con = bus_connection_dup_apparmor_confinement (connection);
+
+ if (is_unconfined (con->label, con->mode))
+ {
+ allow = TRUE;
+ audit = FALSE;
+ goto out;
+ }
+
+ if (!_dbus_string_init (&qstr))
+ goto oom;
+
+ if (!build_service_query (&qstr, con->label, bustype, service_name))
+ {
+ _dbus_string_free (&qstr);
+ goto oom;
+ }
+
+ res = aa_query_label (AA_DBUS_BIND,
+ _dbus_string_get_data (&qstr),
+ _dbus_string_get_length (&qstr),
+ &allow, &audit);
+ _dbus_string_free (&qstr);
+ if (res == -1)
+ {
+ serrno = errno;
+ set_error_from_query_errno (error, serrno);
+ goto audit;
+ }
+
+ /* Don't fail operations on profiles in complain mode */
+ if (modestr_is_complain (con->mode))
+ allow = TRUE;
+
+ if (!allow)
+ dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+ "Connection \"%s\" is not allowed to own the service "
+ "\"%s\" due to AppArmor policy",
+ bus_connection_is_active (connection) ?
+ bus_connection_get_name (connection) : "(inactive)",
+ service_name);
+
+ if (!audit)
+ goto out;
+
+ audit:
+ if (!_dbus_string_init (&auxdata))
+ goto oom;
+ free_auxdata = TRUE;
+
+ if (!_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown"))
+ goto oom;
+
+ if (!_dbus_append_pair_str (&auxdata, "name", service_name))
+ goto oom;
+
+ if (serrno && !_dbus_append_pair_str (&auxdata, "info", strerror (serrno)))
+ goto oom;
+
+ if (!_dbus_append_mask (&auxdata, AA_DBUS_BIND))
+ goto oom;
+
+ if (connection && dbus_connection_get_unix_process_id (connection, &pid) &&
+ !_dbus_append_pair_uint (&auxdata, "pid", pid))
+ goto oom;
+
+ if (con->label && !_dbus_append_pair_str (&auxdata, "label", con->label))
+ goto oom;
+
+ log_message (allow, "bind", &auxdata);
+
+ out:
+ if (con != NULL)
+ bus_apparmor_confinement_unref (con);
+ if (free_auxdata)
+ _dbus_string_free (&auxdata);
+ return allow;
+
+ oom:
+ if (error != NULL && !dbus_error_is_set (error))
+ BUS_SET_OOM (error);
+ allow = FALSE;
+ goto out;
+
+#else
+ return TRUE;
+#endif /* HAVE_APPARMOR */
+}
+
+/**
+ * Check if Apparmor 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.
+ * @param requested_reply TRUE if the message is a reply requested by
+ * proposed_recipient
+ * @param bustype name of the bus
+ * @param msgtype message type (DBUS_MESSAGE_TYPE_METHOD_CALL, etc.)
+ * @param path object path the message should be sent to
+ * @param interface the type of the object instance
+ * @param member the member of the object
+ * @param error_name the name of the error if the message type is error
+ * @param destination name that the message should be sent to
+ * @param source name that the message should be sent from
+ * @param error the reason for failure when FALSE is returned
+ * @returns TRUE if the message is permitted
+ */
+dbus_bool_t
+bus_apparmor_allows_send (DBusConnection *sender,
+ DBusConnection *proposed_recipient,
+ dbus_bool_t requested_reply,
+ const char *bustype,
+ int msgtype,
+ const char *path,
+ const char *interface,
+ const char *member,
+ const char *error_name,
+ const char *destination,
+ const char *source,
+ DBusError *error)
+{
+#ifdef HAVE_APPARMOR
+ BusAppArmorConfinement *src_con = NULL, *dst_con = NULL;
+ DBusString qstr, auxdata;
+ dbus_bool_t src_allow = FALSE, dst_allow = FALSE;
+ dbus_bool_t src_audit = TRUE, dst_audit = TRUE;
+ dbus_bool_t free_auxdata = FALSE;
+ unsigned long pid;
+ int len, res, src_errno = 0, dst_errno = 0;
+ uint32_t src_perm = AA_DBUS_SEND, dst_perm = AA_DBUS_RECEIVE;
+ const char *msgtypestr = dbus_message_type_to_string(msgtype);
+
+ if (!apparmor_enabled)
+ return TRUE;
+
+ _dbus_assert (sender != NULL);
+
+ src_con = bus_connection_dup_apparmor_confinement (sender);
+
+ if (proposed_recipient)
+ {
+ dst_con = bus_connection_dup_apparmor_confinement (proposed_recipient);
+ }
+ else
+ {
+ dst_con = bus_con;
+ bus_apparmor_confinement_ref (dst_con);
+ }
+
+ /* map reply messages to initial send and receive permission. That is
+ * permission to receive a message from X grants permission to reply to X.
+ * And permission to send a message to Y grants permission to receive a reply
+ * from Y. Note that this only applies to requested replies. Unrequested
+ * replies still require a policy query.
+ */
+ if (requested_reply)
+ {
+ /* ignore requested reply messages and let dbus reply mapping handle them
+ * as the send was already allowed
+ */
+ src_allow = TRUE;
+ dst_allow = TRUE;
+ goto out;
+ }
+
+ if (is_unconfined (src_con->label, src_con->mode))
+ {
+ src_allow = TRUE;
+ src_audit = FALSE;
+ }
+ else
+ {
+ if (!_dbus_string_init (&qstr))
+ goto oom;
+
+ if (!build_message_query (&qstr, src_con->label, bustype, destination,
+ dst_con->label, path, interface, member))
+ {
+ _dbus_string_free (&qstr);
+ goto oom;
+ }
+
+ res = aa_query_label (src_perm,
+ _dbus_string_get_data (&qstr),
+ _dbus_string_get_length (&qstr),
+ &src_allow, &src_audit);
+ _dbus_string_free (&qstr);
+ if (res == -1)
+ {
+ src_errno = errno;
+ set_error_from_query_errno (error, src_errno);
+ goto audit;
+ }
+ }
+
+ if (is_unconfined (dst_con->label, dst_con->mode))
+ {
+ dst_allow = TRUE;
+ dst_audit = FALSE;
+ }
+ else
+ {
+ if (!_dbus_string_init (&qstr))
+ goto oom;
+
+ if (!build_message_query (&qstr, dst_con->label, bustype, source,
+ src_con->label, path, interface, member))
+ {
+ _dbus_string_free (&qstr);
+ goto oom;
+ }
+
+ res = aa_query_label (dst_perm,
+ _dbus_string_get_data (&qstr),
+ _dbus_string_get_length (&qstr),
+ &dst_allow, &dst_audit);
+ _dbus_string_free (&qstr);
+ if (res == -1)
+ {
+ dst_errno = errno;
+ set_error_from_query_errno (error, dst_errno);
+ goto audit;
+ }
+ }
+
+ /* Don't fail operations on profiles in complain mode */
+ if (modestr_is_complain (src_con->mode))
+ src_allow = TRUE;
+ if (modestr_is_complain (dst_con->mode))
+ dst_allow = TRUE;
+
+ if (!src_allow || !dst_allow)
+ set_error_from_denied_message (error,
+ sender,
+ proposed_recipient,
+ requested_reply,
+ msgtypestr,
+ path,
+ interface,
+ member,
+ error_name,
+ destination);
+
+ /* Don't audit the message if one of the following conditions is true:
+ * 1) The AppArmor query indicates that auditing should not happen.
+ * 2) The message is a reply type. Reply message are not audited because
+ * the AppArmor policy language does not have the notion of a reply
+ * message. Unrequested replies will be silently discarded if the sender
+ * does not have permission to send to the receiver or if the receiver
+ * does not have permission to receive from the sender.
+ */
+ if ((!src_audit && !dst_audit) ||
+ (msgtype == DBUS_MESSAGE_TYPE_METHOD_RETURN ||
+ msgtype == DBUS_MESSAGE_TYPE_ERROR))
+ goto out;
+
+ audit:
+ if (!_dbus_string_init (&auxdata))
+ goto oom;
+ free_auxdata = TRUE;
+
+ if (!_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown"))
+ goto oom;
+
+ if (path && !_dbus_append_pair_str (&auxdata, "path", path))
+ goto oom;
+
+ if (interface && !_dbus_append_pair_str (&auxdata, "interface", interface))
+ goto oom;
+
+ if (member && !_dbus_append_pair_str (&auxdata, "member", member))
+ goto oom;
+
+ if (error_name && !_dbus_append_pair_str (&auxdata, "error_name", error_name))
+ goto oom;
+
+ len = _dbus_string_get_length (&auxdata);
+
+ if (src_audit)
+ {
+ if (!_dbus_append_mask (&auxdata, src_perm))
+ goto oom;
+
+ if (destination && !_dbus_append_pair_str (&auxdata, "name", destination))
+ goto oom;
+
+ if (sender && dbus_connection_get_unix_process_id (sender, &pid) &&
+ !_dbus_append_pair_uint (&auxdata, "pid", pid))
+ goto oom;
+
+ if (src_con->label &&
+ !_dbus_append_pair_str (&auxdata, "label", src_con->label))
+ goto oom;
+
+ if (proposed_recipient &&
+ dbus_connection_get_unix_process_id (proposed_recipient, &pid) &&
+ !_dbus_append_pair_uint (&auxdata, "peer_pid", pid))
+ goto oom;
+
+ if (dst_con->label &&
+ !_dbus_append_pair_str (&auxdata, "peer_label", dst_con->label))
+ goto oom;
+
+ if (src_errno && !_dbus_append_pair_str (&auxdata, "info", strerror (src_errno)))
+ goto oom;
+
+ if (dst_errno &&
+ !_dbus_append_pair_str (&auxdata, "peer_info", strerror (dst_errno)))
+ goto oom;
+
+ log_message (src_allow, msgtypestr, &auxdata);
+ }
+ if (dst_audit)
+ {
+ _dbus_string_set_length (&auxdata, len);
+
+ if (source && !_dbus_append_pair_str (&auxdata, "name", source))
+ goto oom;
+
+ if (!_dbus_append_mask (&auxdata, dst_perm))
+ goto oom;
+
+ if (proposed_recipient &&
+ dbus_connection_get_unix_process_id (proposed_recipient, &pid) &&
+ !_dbus_append_pair_uint (&auxdata, "pid", pid))
+ goto oom;
+
+ if (dst_con->label &&
+ !_dbus_append_pair_str (&auxdata, "label", dst_con->label))
+ goto oom;
+
+ if (sender && dbus_connection_get_unix_process_id (sender, &pid) &&
+ !_dbus_append_pair_uint (&auxdata, "peer_pid", pid))
+ goto oom;
+
+ if (src_con->label &&
+ !_dbus_append_pair_str (&auxdata, "peer_label", src_con->label))
+ goto oom;
+
+ if (dst_errno && !_dbus_append_pair_str (&auxdata, "info", strerror (dst_errno)))
+ goto oom;
+
+ if (src_errno &&
+ !_dbus_append_pair_str (&auxdata, "peer_info", strerror (src_errno)))
+ goto oom;
+
+ log_message (dst_allow, msgtypestr, &auxdata);
+ }
+
+ out:
+ if (src_con != NULL)
+ bus_apparmor_confinement_unref (src_con);
+ if (dst_con != NULL)
+ bus_apparmor_confinement_unref (dst_con);
+ if (free_auxdata)
+ _dbus_string_free (&auxdata);
+
+ return src_allow && dst_allow;
+
+ oom:
+ if (error != NULL && !dbus_error_is_set (error))
+ BUS_SET_OOM (error);
+ src_allow = FALSE;
+ dst_allow = FALSE;
+ goto out;
+
+#else
+ return TRUE;
+#endif /* HAVE_APPARMOR */
+}
+
+/**
+ * Check if Apparmor security controls allow the connection to eavesdrop on
+ * other connections.
+ *
+ * @param connection the connection attempting to eavesdrop.
+ * @param bustype name of the bus
+ * @param error the reason for failure when FALSE is returned
+ * @returns TRUE if eavesdropping is permitted
+ */
+dbus_bool_t
+bus_apparmor_allows_eavesdropping (DBusConnection *connection,
+ const char *bustype,
+ DBusError *error)
+{
+#ifdef HAVE_APPARMOR
+ BusAppArmorConfinement *con = NULL;
+ DBusString qstr, auxdata;
+ dbus_bool_t allow = FALSE, audit = TRUE;
+ dbus_bool_t free_auxdata = FALSE;
+ unsigned long pid;
+ int res, serrno = 0;
+
+ if (!apparmor_enabled)
+ return TRUE;
+
+ con = bus_connection_dup_apparmor_confinement (connection);
+
+ if (is_unconfined (con->label, con->mode))
+ {
+ allow = TRUE;
+ audit = FALSE;
+ goto out;
+ }
+
+ if (!_dbus_string_init (&qstr))
+ goto oom;
+
+ if (!build_eavesdrop_query (&qstr, con->label, bustype))
+ {
+ _dbus_string_free (&qstr);
+ goto oom;
+ }
+
+ res = aa_query_label (AA_DBUS_EAVESDROP,
+ _dbus_string_get_data (&qstr),
+ _dbus_string_get_length (&qstr),
+ &allow, &audit);
+ _dbus_string_free (&qstr);
+ if (res == -1)
+ {
+ serrno = errno;
+ set_error_from_query_errno (error, serrno);
+ goto audit;
+ }
+
+ /* Don't fail operations on profiles in complain mode */
+ if (modestr_is_complain (con->mode))
+ allow = TRUE;
+
+ if (!allow)
+ dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+ "Connection \"%s\" is not allowed to eavesdrop due to "
+ "AppArmor policy",
+ bus_connection_is_active (connection) ?
+ bus_connection_get_name (connection) : "(inactive)");
+
+ if (!audit)
+ goto out;
+
+ audit:
+ if (!_dbus_string_init (&auxdata))
+ goto oom;
+ free_auxdata = TRUE;
+
+ if (!_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown"))
+ goto oom;
+
+ if (serrno && !_dbus_append_pair_str (&auxdata, "info", strerror (serrno)))
+ goto oom;
+
+ if (!_dbus_append_pair_str (&auxdata, "mask", "eavesdrop"))
+ goto oom;
+
+ if (connection && dbus_connection_get_unix_process_id (connection, &pid) &&
+ !_dbus_append_pair_uint (&auxdata, "pid", pid))
+ goto oom;
+
+ if (con->label && !_dbus_append_pair_str (&auxdata, "label", con->label))
+ goto oom;
+
+ log_message (allow, "eavesdrop", &auxdata);
+
+ out:
+ if (con != NULL)
+ bus_apparmor_confinement_unref (con);
+ if (free_auxdata)
+ _dbus_string_free (&auxdata);
+
+ return allow;
+
+ oom:
+ if (error != NULL && !dbus_error_is_set (error))
+ BUS_SET_OOM (error);
+ allow = FALSE;
+ goto out;
+
+#else
+ return TRUE;
+#endif /* HAVE_APPARMOR */
+}
diff --git a/bus/apparmor.h b/bus/apparmor.h
new file mode 100644
index 00000000..4a47aecc
--- /dev/null
+++ b/bus/apparmor.h
@@ -0,0 +1,66 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ * apparmor.c AppArmor security checks for D-Bus
+ *
+ * Authors: John Johansen <john.johansen@canonical.com>
+ * Tyler Hicks <tyhicks@canonical.com>
+ * Based on: selinux.h by 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_APPARMOR_H
+#define BUS_APPARMOR_H
+
+#include <dbus/dbus.h>
+#include "bus.h"
+
+void bus_apparmor_audit_init (void);
+dbus_bool_t bus_apparmor_pre_init (void);
+dbus_bool_t bus_apparmor_set_mode_from_config (const char *mode,
+ DBusError *error);
+dbus_bool_t bus_apparmor_full_init (DBusError *error);
+void bus_apparmor_shutdown (void);
+dbus_bool_t bus_apparmor_enabled (void);
+
+void bus_apparmor_confinement_unref (BusAppArmorConfinement *confinement);
+void bus_apparmor_confinement_ref (BusAppArmorConfinement *confinement);
+BusAppArmorConfinement* bus_apparmor_init_connection_confinement (DBusConnection *connection,
+ DBusError *error);
+
+dbus_bool_t bus_apparmor_allows_acquire_service (DBusConnection *connection,
+ const char *bustype,
+ const char *service_name,
+ DBusError *error);
+dbus_bool_t bus_apparmor_allows_send (DBusConnection *sender,
+ DBusConnection *proposed_recipient,
+ dbus_bool_t requested_reply,
+ const char *bustype,
+ int msgtype,
+ const char *path,
+ const char *interface,
+ const char *member,
+ const char *error_name,
+ const char *destination,
+ const char *source,
+ DBusError *error);
+
+dbus_bool_t bus_apparmor_allows_eavesdropping (DBusConnection *connection,
+ const char *bustype,
+ DBusError *error);
+
+#endif /* BUS_APPARMOR_H */
diff --git a/bus/bus.c b/bus/bus.c
index f0d980e5..1aa893b6 100644
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -34,6 +34,7 @@
#include "config-parser.h"
#include "signals.h"
#include "selinux.h"
+#include "apparmor.h"
#include "dir-watch.h"
#include <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
@@ -671,7 +672,7 @@ raise_file_descriptor_limit (BusContext *context)
if (context->initial_fd_limit == NULL)
{
- bus_context_log (context, DBUS_SYSTEM_LOG_INFO,
+ bus_context_log (context, DBUS_SYSTEM_LOG_WARNING,
"%s: %s", error.name, error.message);
dbus_error_free (&error);
return;
@@ -686,7 +687,7 @@ raise_file_descriptor_limit (BusContext *context)
*/
if (!_dbus_rlimit_raise_fd_limit_if_privileged (65536, &error))
{
- bus_context_log (context, DBUS_SYSTEM_LOG_INFO,
+ bus_context_log (context, DBUS_SYSTEM_LOG_WARNING,
"%s: %s", error.name, error.message);
dbus_error_free (&error);
return;
@@ -765,7 +766,8 @@ bus_context_new (const DBusString *config_file,
}
context->refcount = 1;
- _dbus_generate_uuid (&context->uuid);
+ if (!_dbus_generate_uuid (&context->uuid, error))
+ goto failed;
if (!_dbus_string_copy_data (config_file, &context->config_file))
{
@@ -933,6 +935,20 @@ bus_context_new (const DBusString *config_file,
bus_context_log (context, DBUS_SYSTEM_LOG_FATAL, "SELinux enabled but D-Bus initialization failed; check system log\n");
}
+ if (!bus_apparmor_full_init (error))
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ goto failed;
+ }
+
+ if (bus_apparmor_enabled ())
+ {
+ /* Only print AppArmor mediation message when syslog support is enabled */
+ if (context->syslog)
+ bus_context_log (context, DBUS_SYSTEM_LOG_INFO,
+ "AppArmor D-Bus mediation is enabled\n");
+ }
+
if (!process_config_postinit (context, parser, error))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
@@ -960,6 +976,9 @@ bus_context_new (const DBusString *config_file,
/* FIXME - why not just put this in full_init() below? */
bus_selinux_audit_init ();
#endif
+#ifdef HAVE_APPARMOR
+ bus_apparmor_audit_init ();
+#endif
}
dbus_server_free_data_slot (&server_data_slot);
@@ -1325,9 +1344,6 @@ bus_context_get_initial_fd_limit (BusContext *context)
}
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;
@@ -1339,6 +1355,10 @@ bus_context_log (BusContext *context, DBusSystemLogSeverity severity, const char
vfprintf (stderr, msg, args);
fprintf (stderr, "\n");
va_end (args);
+
+ if (severity == DBUS_SYSTEM_LOG_FATAL)
+ _dbus_exit (1);
+
return;
}
@@ -1373,6 +1393,49 @@ nonnull (const char *maybe_null,
return (maybe_null ? maybe_null : if_null);
}
+void
+bus_context_log_literal (BusContext *context,
+ DBusSystemLogSeverity severity,
+ const char *msg)
+{
+ if (!context->syslog)
+ {
+ fputs (msg, stderr);
+ fputc ('\n', stderr);
+
+ if (severity == DBUS_SYSTEM_LOG_FATAL)
+ _dbus_exit (1);
+ }
+ else
+ {
+ _dbus_system_log (severity, "%s%s", nonnull (context->log_prefix, ""),
+ msg);
+ }
+}
+
+void
+bus_context_log_and_set_error (BusContext *context,
+ DBusSystemLogSeverity severity,
+ DBusError *error,
+ const char *name,
+ const char *msg,
+ ...)
+{
+ DBusError stack_error = DBUS_ERROR_INIT;
+ va_list args;
+
+ va_start (args, msg);
+ _dbus_set_error_valist (&stack_error, name, msg, args);
+ va_end (args);
+
+ /* If we hit OOM while setting the error, this will syslog "out of memory"
+ * which is itself an indication that something is seriously wrong */
+ bus_context_log_literal (context, DBUS_SYSTEM_LOG_SECURITY,
+ stack_error.message);
+
+ dbus_move_error (&stack_error, error);
+}
+
/*
* Log something about a message, usually that it was rejected.
*/
@@ -1431,7 +1494,7 @@ complain_about_message (BusContext *context,
/* If we hit OOM while setting the error, this will syslog "out of memory"
* which is itself an indication that something is seriously wrong */
if (log)
- bus_context_log (context, DBUS_SYSTEM_LOG_SECURITY, "%s",
+ bus_context_log_literal (context, DBUS_SYSTEM_LOG_SECURITY,
stack_error.message);
dbus_move_error (&stack_error, error);
@@ -1459,7 +1522,7 @@ bus_context_check_security_policy (BusContext *context,
DBusMessage *message,
DBusError *error)
{
- const char *dest;
+ const char *src, *dest;
BusClientPolicy *sender_policy;
BusClientPolicy *recipient_policy;
dbus_int32_t toggles;
@@ -1468,6 +1531,7 @@ bus_context_check_security_policy (BusContext *context,
dbus_bool_t requested_reply;
type = dbus_message_get_type (message);
+ src = dbus_message_get_sender (message);
dest = dbus_message_get_destination (message);
/* dispatch.c was supposed to ensure these invariants */
@@ -1500,30 +1564,6 @@ bus_context_check_security_policy (BusContext *context,
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))
- {
- /* don't syslog this, just set the error: avc_has_perm should
- * have already written to either the audit log or syslog */
- complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
- "An SELinux policy prevents this sender from sending this "
- "message to this recipient",
- 0, message, sender, proposed_recipient, FALSE, FALSE, error);
- _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);
@@ -1554,6 +1594,51 @@ bus_context_check_security_policy (BusContext *context,
}
else
{
+ sender_policy = 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))
+ {
+ /* don't syslog this, just set the error: avc_has_perm should
+ * have already written to either the audit log or syslog */
+ complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
+ "An SELinux policy prevents this sender from sending this "
+ "message to this recipient",
+ 0, message, sender, proposed_recipient, FALSE, FALSE, error);
+ _dbus_verbose ("SELinux security check denying send to service\n");
+ }
+
+ return FALSE;
+ }
+
+ /* next verify AppArmor access controls. If allowed then
+ * go on with the standard checks.
+ */
+ if (!bus_apparmor_allows_send (sender, proposed_recipient,
+ requested_reply,
+ bus_context_get_type (context),
+ dbus_message_get_type (message),
+ dbus_message_get_path (message),
+ dbus_message_get_interface (message),
+ dbus_message_get_member (message),
+ dbus_message_get_error_name (message),
+ dest ? dest : DBUS_SERVICE_DBUS,
+ src ? src : DBUS_SERVICE_DBUS,
+ error))
+ return FALSE;
+
+ if (!bus_connection_is_active (sender))
+ {
/* Policy for inactive connections is that they can only send
* the hello message to the bus driver
*/
diff --git a/bus/bus.h b/bus/bus.h
index dac6ea5e..3fab59ff 100644
--- a/bus/bus.h
+++ b/bus/bus.h
@@ -38,6 +38,7 @@ typedef struct BusClientPolicy BusClientPolicy;
typedef struct BusPolicyRule BusPolicyRule;
typedef struct BusRegistry BusRegistry;
typedef struct BusSELinuxID BusSELinuxID;
+typedef struct BusAppArmorConfinement BusAppArmorConfinement;
typedef struct BusService BusService;
typedef struct BusOwner BusOwner;
typedef struct BusTransaction BusTransaction;
@@ -120,7 +121,16 @@ DBusRLimit * bus_context_get_initial_fd_limit (BusContext
void bus_context_log (BusContext *context,
DBusSystemLogSeverity severity,
const char *msg,
- ...);
+ ...) _DBUS_GNUC_PRINTF (3, 4);
+void bus_context_log_literal (BusContext *context,
+ DBusSystemLogSeverity severity,
+ const char *msg);
+void bus_context_log_and_set_error (BusContext *context,
+ DBusSystemLogSeverity severity,
+ DBusError *error,
+ const char *name,
+ const char *msg,
+ ...) _DBUS_GNUC_PRINTF (5, 6);
dbus_bool_t bus_context_check_security_policy (BusContext *context,
BusTransaction *transaction,
DBusConnection *sender,
diff --git a/bus/config-parser-common.c b/bus/config-parser-common.c
index c522ff49..5db6b289 100644
--- a/bus/config-parser-common.c
+++ b/bus/config-parser-common.c
@@ -127,6 +127,10 @@ bus_config_parser_element_name_to_type (const char *name)
{
return ELEMENT_ALLOW_ANONYMOUS;
}
+ else if (strcmp (name, "apparmor") == 0)
+ {
+ return ELEMENT_APPARMOR;
+ }
return ELEMENT_NONE;
}
@@ -181,6 +185,8 @@ bus_config_parser_element_type_to_name (ElementType type)
return "keep_umask";
case ELEMENT_ALLOW_ANONYMOUS:
return "allow_anonymous";
+ case ELEMENT_APPARMOR:
+ return "apparmor";
}
_dbus_assert_not_reached ("bad element type");
diff --git a/bus/config-parser-common.h b/bus/config-parser-common.h
index 186bf4cf..382a0141 100644
--- a/bus/config-parser-common.h
+++ b/bus/config-parser-common.h
@@ -49,7 +49,8 @@ typedef enum
ELEMENT_STANDARD_SYSTEM_SERVICEDIRS,
ELEMENT_KEEP_UMASK,
ELEMENT_SYSLOG,
- ELEMENT_ALLOW_ANONYMOUS
+ ELEMENT_ALLOW_ANONYMOUS,
+ ELEMENT_APPARMOR
} ElementType;
ElementType bus_config_parser_element_name_to_type (const char *element_name);
diff --git a/bus/config-parser.c b/bus/config-parser.c
index ee2d4e7d..3f59730b 100644
--- a/bus/config-parser.c
+++ b/bus/config-parser.c
@@ -28,6 +28,7 @@
#include "utils.h"
#include "policy.h"
#include "selinux.h"
+#include "apparmor.h"
#include <dbus/dbus-list.h>
#include <dbus/dbus-internals.h>
#include <dbus/dbus-misc.h>
@@ -1136,6 +1137,27 @@ start_busconfig_child (BusConfigParser *parser,
return TRUE;
}
+ else if (element_type == ELEMENT_APPARMOR)
+ {
+ Element *e;
+ const char *mode;
+
+ if ((e = push_element (parser, ELEMENT_APPARMOR)) == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!locate_attributes (parser, "apparmor",
+ attribute_names,
+ attribute_values,
+ error,
+ "mode", &mode,
+ NULL))
+ return FALSE;
+
+ return bus_apparmor_set_mode_from_config (mode, error);
+ }
else
{
dbus_set_error (error, DBUS_ERROR_FAILED,
@@ -2074,6 +2096,7 @@ bus_config_parser_end_element (BusConfigParser *parser,
case ELEMENT_STANDARD_SESSION_SERVICEDIRS:
case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:
case ELEMENT_ALLOW_ANONYMOUS:
+ case ELEMENT_APPARMOR:
break;
}
@@ -2242,7 +2265,15 @@ include_dir (BusConfigParser *parser,
dir = _dbus_directory_open (dirname, error);
if (dir == NULL)
- goto failed;
+ {
+ if (dbus_error_has_name (error, DBUS_ERROR_FILE_NOT_FOUND))
+ {
+ dbus_error_free (error);
+ goto success;
+ }
+ else
+ goto failed;
+ }
dbus_error_init (&tmp_error);
while (_dbus_directory_get_next_file (dir, &filename, &tmp_error))
@@ -2312,6 +2343,7 @@ include_dir (BusConfigParser *parser,
goto failed;
}
+ success:
retval = TRUE;
failed:
@@ -2373,6 +2405,7 @@ bus_config_parser_content (BusConfigParser *parser,
case ELEMENT_ALLOW_ANONYMOUS:
case ELEMENT_SELINUX:
case ELEMENT_ASSOCIATE:
+ case ELEMENT_APPARMOR:
if (all_whitespace (content))
return TRUE;
else
diff --git a/bus/connection.c b/bus/connection.c
index 7107434f..95e20a6e 100644
--- a/bus/connection.c
+++ b/bus/connection.c
@@ -30,10 +30,12 @@
#include "signals.h"
#include "expirelist.h"
#include "selinux.h"
+#include "apparmor.h"
#include <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
#include <dbus/dbus-timeout.h>
#include <dbus/dbus-connection-internal.h>
+#include <dbus/dbus-internals.h>
/* Trim executed commands to this length; we want to keep logs readable */
#define MAX_LOG_COMMAND_LEN 50
@@ -64,6 +66,11 @@ struct BusConnections
int stamp; /**< Incrementing number */
BusExpireList *pending_replies; /**< List of pending replies */
+ /** List of all monitoring connections, a subset of completed.
+ * Each member is a #DBusConnection. */
+ DBusList *monitors;
+ BusMatchmaker *monitor_matchmaker;
+
#ifdef DBUS_ENABLE_STATS
int total_match_rules;
int peak_match_rules;
@@ -94,6 +101,7 @@ typedef struct
char *cached_loginfo_string;
BusSELinuxID *selinux_id;
+ BusAppArmorConfinement *apparmor_confinement;
long connection_tv_sec; /**< Time when we connected (seconds component) */
long connection_tv_usec; /**< Time when we connected (microsec component) */
@@ -105,6 +113,9 @@ typedef struct
#endif
int n_pending_unix_fds;
DBusTimeout *pending_unix_fds_timeout;
+
+ /** non-NULL if and only if this is a monitor */
+ DBusList *link_in_monitors;
} BusConnectionData;
static dbus_bool_t bus_pending_reply_expired (BusExpireList *list,
@@ -124,6 +135,7 @@ connection_get_loop (DBusConnection *connection)
BusConnectionData *d;
d = BUS_CONNECTION_DATA (connection);
+ _dbus_assert(d != NULL);
return bus_context_get_loop (d->connections->context);
}
@@ -283,6 +295,17 @@ bus_connection_disconnected (DBusConnection *connection)
bus_connection_remove_transactions (connection);
+ if (d->link_in_monitors != NULL)
+ {
+ BusMatchmaker *mm = d->connections->monitor_matchmaker;
+
+ if (mm != NULL)
+ bus_matchmaker_disconnected (mm, connection);
+
+ _dbus_list_remove_link (&d->connections->monitors, d->link_in_monitors);
+ d->link_in_monitors = NULL;
+ }
+
if (d->link_in_connection_list != NULL)
{
if (d->name != NULL)
@@ -420,6 +443,9 @@ free_connection_data (void *data)
if (d->selinux_id)
bus_selinux_id_unref (d->selinux_id);
+
+ if (d->apparmor_confinement)
+ bus_apparmor_confinement_unref (d->apparmor_confinement);
dbus_free (d->cached_loginfo_string);
@@ -513,7 +539,10 @@ bus_connections_unref (BusConnections *connections)
}
_dbus_assert (connections->n_incomplete == 0);
-
+
+ /* drop all monitors */
+ _dbus_list_clear (&connections->monitors);
+
/* drop all real connections */
while (connections->completed != NULL)
{
@@ -537,7 +566,10 @@ bus_connections_unref (BusConnections *connections)
_dbus_timeout_unref (connections->expire_timeout);
_dbus_hash_table_unref (connections->completed_by_user);
-
+
+ if (connections->monitor_matchmaker != NULL)
+ bus_matchmaker_unref (connections->monitor_matchmaker);
+
dbus_free (connections);
dbus_connection_free_data_slot (&connection_data_slot);
@@ -608,9 +640,12 @@ static void
check_pending_fds_cb (DBusConnection *connection)
{
BusConnectionData *d = BUS_CONNECTION_DATA (connection);
- int n_pending_unix_fds_old = d->n_pending_unix_fds;
+ int n_pending_unix_fds_old;
int n_pending_unix_fds_new;
+ _dbus_assert(d != NULL);
+
+ n_pending_unix_fds_old = d->n_pending_unix_fds;
n_pending_unix_fds_new = _dbus_connection_get_pending_fds_count (connection);
_dbus_verbose ("Pending fds count changed on connection %p: %d -> %d\n",
@@ -689,6 +724,19 @@ bus_connections_setup_connection (BusConnections *connections,
goto out;
}
+ d->apparmor_confinement = bus_apparmor_init_connection_confinement (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,
@@ -776,6 +824,10 @@ bus_connections_setup_connection (BusConnections *connections,
if (d->selinux_id)
bus_selinux_id_unref (d->selinux_id);
d->selinux_id = NULL;
+
+ if (d->apparmor_confinement)
+ bus_apparmor_confinement_unref (d->apparmor_confinement);
+ d->apparmor_confinement = NULL;
if (!dbus_connection_set_watch_functions (connection,
NULL, NULL, NULL,
@@ -863,7 +915,7 @@ bus_connections_expire_incomplete (BusConnections *connections)
/* Unfortunately, we can't identify the connection: it doesn't
* have a unique name yet, we don't know its uid/pid yet,
* and so on. */
- bus_context_log (connections->context, DBUS_SYSTEM_LOG_INFO,
+ bus_context_log (connections->context, DBUS_SYSTEM_LOG_WARNING,
"Connection has not authenticated soon enough, closing it "
"(auth_timeout=%dms, elapsed: %.0fms)",
auth_timeout, elapsed);
@@ -965,6 +1017,7 @@ bus_connection_get_loginfo (DBusConnection *connection)
BusConnectionData *d;
d = BUS_CONNECTION_DATA (connection);
+ _dbus_assert(d != NULL);
if (!bus_connection_is_active (connection))
return "inactive";
@@ -1176,6 +1229,19 @@ bus_connection_get_selinux_id (DBusConnection *connection)
return d->selinux_id;
}
+BusAppArmorConfinement*
+bus_connection_dup_apparmor_confinement (DBusConnection *connection)
+{
+ BusConnectionData *d;
+
+ d = BUS_CONNECTION_DATA (connection);
+
+ _dbus_assert (d != NULL);
+
+ bus_apparmor_confinement_ref (d->apparmor_confinement);
+ return d->apparmor_confinement;
+}
+
/**
* Checks whether the connection is registered with the message bus.
*
@@ -1188,8 +1254,9 @@ bus_connection_is_active (DBusConnection *connection)
BusConnectionData *d;
d = BUS_CONNECTION_DATA (connection);
+ _dbus_assert(d != NULL);
- return d != NULL && d->name != NULL;
+ return d->name != NULL;
}
dbus_bool_t
@@ -1256,6 +1323,10 @@ bus_connection_send_oom_error (DBusConnection *connection,
_dbus_assert (d != NULL);
_dbus_assert (d->oom_message != NULL);
+ bus_context_log (d->connections->context, DBUS_SYSTEM_LOG_WARNING,
+ "dbus-daemon transaction failed (OOM), sending error to "
+ "sender %s", bus_connection_get_loginfo (connection));
+
/* 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)))
@@ -1627,7 +1698,12 @@ bus_pending_reply_send_no_reply (BusConnections *connections,
DBUS_ERROR_NO_REPLY))
goto out;
- errmsg = "Message did not receive a reply (timeout by message bus)";
+ /* If you change these messages, adjust test/dbus-daemon.c to match */
+ if (pending->will_send_reply == NULL)
+ errmsg = "Message recipient disconnected from message bus without replying";
+ else
+ 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;
@@ -2099,11 +2175,95 @@ bus_transaction_get_context (BusTransaction *transaction)
return transaction->context;
}
+/**
+ * Reserve enough memory to capture the given message if the
+ * transaction goes through.
+ */
+dbus_bool_t
+bus_transaction_capture (BusTransaction *transaction,
+ DBusConnection *sender,
+ DBusMessage *message)
+{
+ BusConnections *connections;
+ BusMatchmaker *mm;
+ DBusList *link;
+ DBusList *recipients = NULL;
+ dbus_bool_t ret = FALSE;
+
+ connections = bus_context_get_connections (transaction->context);
+
+ /* shortcut: don't compose the message unless someone wants it */
+ if (connections->monitors == NULL)
+ return TRUE;
+
+ mm = connections->monitor_matchmaker;
+ /* This is non-null if there has ever been a monitor - we don't GC it.
+ * There's little point, since there is up to 1 per process. */
+ _dbus_assert (mm != NULL);
+
+ if (!bus_matchmaker_get_recipients (mm, connections, sender, NULL, message,
+ &recipients))
+ goto out;
+
+ for (link = _dbus_list_get_first_link (&recipients);
+ link != NULL;
+ link = _dbus_list_get_next_link (&recipients, link))
+ {
+ DBusConnection *recipient = link->data;
+
+ if (!bus_transaction_send (transaction, recipient, message))
+ goto out;
+ }
+
+ ret = TRUE;
+
+out:
+ _dbus_list_clear (&recipients);
+ return ret;
+}
+
+dbus_bool_t
+bus_transaction_capture_error_reply (BusTransaction *transaction,
+ const DBusError *error,
+ DBusMessage *in_reply_to)
+{
+ BusConnections *connections;
+ DBusMessage *reply;
+ dbus_bool_t ret = FALSE;
+
+ _dbus_assert (error != NULL);
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+
+ connections = bus_context_get_connections (transaction->context);
+
+ /* shortcut: don't compose the message unless someone wants it */
+ if (connections->monitors == NULL)
+ return TRUE;
+
+ reply = dbus_message_new_error (in_reply_to,
+ error->name,
+ error->message);
+
+ if (reply == NULL)
+ return FALSE;
+
+ if (!dbus_message_set_sender (reply, DBUS_SERVICE_DBUS))
+ goto out;
+
+ ret = bus_transaction_capture (transaction, NULL, reply);
+
+out:
+ dbus_message_unref (reply);
+ return ret;
+}
+
dbus_bool_t
bus_transaction_send_from_driver (BusTransaction *transaction,
DBusConnection *connection,
DBusMessage *message)
{
+ DBusError error = DBUS_ERROR_INIT;
+
/* We have to set the sender to the driver, and have
* to check security policy since it was not done in
* dispatch.c
@@ -2128,14 +2288,34 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
/* 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.
+
+ /* Capture it for monitors, even if the real recipient's receive policy
+ * does not allow it to receive this message from us (which would be odd).
+ */
+ if (!bus_transaction_capture (transaction, NULL, message))
+ return FALSE;
+
+ /* If security policy doesn't allow the message, we would silently
+ * eat it; the driver doesn't care about getting a reply. However,
+ * if we're actively capturing messages, it's nice to log that we
+ * tried to send it and did not allow ourselves to do so.
*/
if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
transaction,
- NULL, connection, connection, message, NULL))
- return TRUE;
+ NULL, connection, connection, message, &error))
+ {
+ if (!bus_transaction_capture_error_reply (transaction, &error, message))
+ {
+ bus_context_log (transaction->context, DBUS_SYSTEM_LOG_WARNING,
+ "message from dbus-daemon rejected but not enough "
+ "memory to capture it");
+ }
+
+ /* This is not fatal to the transaction so silently eat the disallowed
+ * message (see reasoning above) */
+ dbus_error_free (&error);
+ return TRUE;
+ }
return bus_transaction_send (transaction, connection, message);
}
@@ -2476,6 +2656,8 @@ bus_connection_get_peak_match_rules (DBusConnection *connection)
BusConnectionData *d;
d = BUS_CONNECTION_DATA (connection);
+ _dbus_assert(d != NULL);
+
return d->peak_match_rules;
}
@@ -2485,6 +2667,145 @@ bus_connection_get_peak_bus_names (DBusConnection *connection)
BusConnectionData *d;
d = BUS_CONNECTION_DATA (connection);
+ _dbus_assert(d != NULL);
+
return d->peak_bus_names;
}
#endif /* DBUS_ENABLE_STATS */
+
+dbus_bool_t
+bus_connection_is_monitor (DBusConnection *connection)
+{
+ BusConnectionData *d;
+
+ d = BUS_CONNECTION_DATA (connection);
+ _dbus_assert(d != NULL);
+
+ return d->link_in_monitors != NULL;
+}
+
+static dbus_bool_t
+bcd_add_monitor_rules (BusConnectionData *d,
+ DBusConnection *connection,
+ DBusList **rules)
+{
+ BusMatchmaker *mm = d->connections->monitor_matchmaker;
+ DBusList *iter;
+
+ if (mm == NULL)
+ {
+ mm = bus_matchmaker_new ();
+
+ if (mm == NULL)
+ return FALSE;
+
+ d->connections->monitor_matchmaker = mm;
+ }
+
+ for (iter = _dbus_list_get_first_link (rules);
+ iter != NULL;
+ iter = _dbus_list_get_next_link (rules, iter))
+ {
+ if (!bus_matchmaker_add_rule (mm, iter->data))
+ {
+ bus_matchmaker_disconnected (mm, connection);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+bcd_drop_monitor_rules (BusConnectionData *d,
+ DBusConnection *connection)
+{
+ BusMatchmaker *mm = d->connections->monitor_matchmaker;
+
+ if (mm != NULL)
+ bus_matchmaker_disconnected (mm, connection);
+}
+
+dbus_bool_t
+bus_connection_be_monitor (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusList **rules,
+ DBusError *error)
+{
+ BusConnectionData *d;
+ DBusList *link;
+ DBusList *tmp;
+ DBusList *iter;
+
+ d = BUS_CONNECTION_DATA (connection);
+ _dbus_assert (d != NULL);
+
+ link = _dbus_list_alloc_link (connection);
+
+ if (link == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!bcd_add_monitor_rules (d, connection, rules))
+ {
+ _dbus_list_free_link (link);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ /* release all its names */
+ if (!_dbus_list_copy (&d->services_owned, &tmp))
+ {
+ bcd_drop_monitor_rules (d, connection);
+ _dbus_list_free_link (link);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ for (iter = _dbus_list_get_first_link (&tmp);
+ iter != NULL;
+ iter = _dbus_list_get_next_link (&tmp, iter))
+ {
+ BusService *service = iter->data;
+
+ /* This call is transactional: if there isn't enough memory to
+ * do everything, then the service gets all its names back when
+ * the transaction is cancelled due to OOM. */
+ if (!bus_service_remove_owner (service, connection, transaction, error))
+ {
+ bcd_drop_monitor_rules (d, connection);
+ _dbus_list_free_link (link);
+ _dbus_list_clear (&tmp);
+ return FALSE;
+ }
+ }
+
+ /* We have now done everything that can fail, so there is no problem
+ * with doing the irrevocable stuff. */
+
+ _dbus_list_clear (&tmp);
+
+ bus_context_log (transaction->context, DBUS_SYSTEM_LOG_INFO,
+ "Connection %s (%s) became a monitor.", d->name,
+ d->cached_loginfo_string);
+
+ if (d->n_match_rules > 0)
+ {
+ BusMatchmaker *mm;
+
+ mm = bus_context_get_matchmaker (d->connections->context);
+ bus_matchmaker_disconnected (mm, connection);
+ }
+
+ /* flag it as a monitor */
+ d->link_in_monitors = link;
+ _dbus_list_append_link (&d->connections->monitors, link);
+
+ /* it isn't allowed to reply, and it is no longer relevant whether it
+ * receives replies */
+ bus_connection_drop_pending_replies (d->connections, connection);
+
+ return TRUE;
+}
diff --git a/bus/connection.h b/bus/connection.h
index 6fbcd38d..8c68d0a0 100644
--- a/bus/connection.h
+++ b/bus/connection.h
@@ -54,6 +54,7 @@ BusActivation* bus_connection_get_activation (DBusConnection
BusMatchmaker* bus_connection_get_matchmaker (DBusConnection *connection);
const char * bus_connection_get_loginfo (DBusConnection *connection);
BusSELinuxID* bus_connection_get_selinux_id (DBusConnection *connection);
+BusAppArmorConfinement* bus_connection_dup_apparmor_confinement (DBusConnection *connection);
dbus_bool_t bus_connections_check_limits (BusConnections *connections,
DBusConnection *requesting_completion,
DBusError *error);
@@ -116,6 +117,12 @@ dbus_bool_t bus_connection_get_unix_groups (DBusConnection *connecti
DBusError *error);
BusClientPolicy* bus_connection_get_policy (DBusConnection *connection);
+dbus_bool_t bus_connection_is_monitor (DBusConnection *connection);
+dbus_bool_t bus_connection_be_monitor (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusList **rules,
+ DBusError *error);
+
/* transaction API so we can send or not send a block of messages as a whole */
typedef void (* BusTransactionCancelFunction) (void *data);
@@ -125,6 +132,12 @@ BusContext* bus_transaction_get_context (BusTransaction *
dbus_bool_t bus_transaction_send (BusTransaction *transaction,
DBusConnection *connection,
DBusMessage *message);
+dbus_bool_t bus_transaction_capture (BusTransaction *transaction,
+ DBusConnection *connection,
+ DBusMessage *message);
+dbus_bool_t bus_transaction_capture_error_reply (BusTransaction *transaction,
+ const DBusError *error,
+ DBusMessage *in_reply_to);
dbus_bool_t bus_transaction_send_from_driver (BusTransaction *transaction,
DBusConnection *connection,
DBusMessage *message);
diff --git a/bus/dir-watch-inotify.c b/bus/dir-watch-inotify.c
index 49ebc721..ce19fdc8 100644
--- a/bus/dir-watch-inotify.c
+++ b/bus/dir-watch-inotify.c
@@ -38,6 +38,7 @@
#include <dbus/dbus-internals.h>
#include <dbus/dbus-list.h>
+#include <dbus/dbus-sysdeps-unix.h>
#include <dbus/dbus-watch.h>
#include "dir-watch.h"
@@ -236,6 +237,11 @@ _init_inotify (BusContext *context)
_dbus_warn ("Cannot initialize inotify\n");
goto out;
}
+
+ /* In the inotify_init1 case this is unnecessary but harmless,
+ * in the other cases it's necessary */
+ _dbus_fd_set_close_on_exec (inotify_fd);
+
loop = bus_context_get_loop (context);
_dbus_loop_ref (loop);
diff --git a/bus/dir-watch-kqueue.c b/bus/dir-watch-kqueue.c
index 33d5e95d..c1e83245 100644
--- a/bus/dir-watch-kqueue.c
+++ b/bus/dir-watch-kqueue.c
@@ -38,6 +38,7 @@
#include <dbus/dbus-internals.h>
#include <dbus/dbus-list.h>
+#include <dbus/dbus-sysdeps-unix.h>
#include "dir-watch.h"
#define MAX_DIRS_TO_WATCH 128
@@ -202,6 +203,9 @@ bus_set_watched_dirs (BusContext *context, DBusList **directories)
DBusList *link;
int i, j, fd;
struct kevent ev;
+#ifdef O_CLOEXEC
+ dbus_bool_t cloexec_done = 0;
+#endif
if (!_init_kqueue (context))
goto out;
@@ -259,7 +263,15 @@ bus_set_watched_dirs (BusContext *context, DBusList **directories)
/* FIXME - less lame error handling for failing to add a watch;
* we may need to sleep.
*/
+#ifdef O_CLOEXEC
fd = open (new_dirs[i], O_RDONLY | O_CLOEXEC);
+ cloexec_done = (fd >= 0);
+
+ if (fd < 0 && errno == EINVAL)
+#endif
+ {
+ fd = open (new_dirs[i], O_RDONLY);
+ }
if (fd < 0)
{
if (errno != ENOENT)
@@ -274,6 +286,12 @@ bus_set_watched_dirs (BusContext *context, DBusList **directories)
continue;
}
}
+#ifdef O_CLOEXEC
+ if (!cloexec_done)
+#endif
+ {
+ _dbus_fd_set_close_on_exec (fd);
+ }
EV_SET (&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_RENAME, 0, 0);
diff --git a/bus/dispatch.c b/bus/dispatch.c
index 7a61953f..3ea944ab 100644
--- a/bus/dispatch.c
+++ b/bus/dispatch.c
@@ -47,6 +47,13 @@
* dbus_connection_open_private() does not block. */
#define TEST_DEBUG_PIPE "debug-pipe:name=test-server"
+static inline const char *
+nonnull (const char *maybe_null,
+ const char *if_null)
+{
+ return (maybe_null ? maybe_null : if_null);
+}
+
static dbus_bool_t
send_one_message (DBusConnection *connection,
BusContext *context,
@@ -56,17 +63,47 @@ send_one_message (DBusConnection *connection,
BusTransaction *transaction,
DBusError *error)
{
+ DBusError stack_error = DBUS_ERROR_INIT;
+
if (!bus_context_check_security_policy (context, transaction,
sender,
addressed_recipient,
connection,
message,
- NULL))
- return TRUE; /* silently don't send it */
+ &stack_error))
+ {
+ if (!bus_transaction_capture_error_reply (transaction, &stack_error,
+ message))
+ {
+ bus_context_log (context, DBUS_SYSTEM_LOG_WARNING,
+ "broadcast rejected, but not enough "
+ "memory to tell monitors");
+ }
+
+ dbus_error_free (&stack_error);
+ return TRUE; /* don't send it but don't return an error either */
+ }
if (dbus_message_contains_unix_fds(message) &&
!dbus_connection_can_send_type(connection, DBUS_TYPE_UNIX_FD))
- return TRUE; /* silently don't send it */
+ {
+ dbus_set_error (&stack_error, DBUS_ERROR_NOT_SUPPORTED,
+ "broadcast cannot be delivered to %s (%s) because "
+ "it does not support receiving Unix fds",
+ bus_connection_get_name (connection),
+ bus_connection_get_loginfo (connection));
+
+ if (!bus_transaction_capture_error_reply (transaction, &stack_error,
+ message))
+ {
+ bus_context_log (context, DBUS_SYSTEM_LOG_WARNING,
+ "broadcast with Unix fd not delivered, but not "
+ "enough memory to tell monitors");
+ }
+
+ dbus_error_free (&stack_error);
+ return TRUE; /* don't send it but don't return an error either */
+ }
if (!bus_transaction_send (transaction,
connection,
@@ -200,6 +237,54 @@ bus_dispatch (DBusConnection *connection,
/* Ref connection in case we disconnect it at some point in here */
dbus_connection_ref (connection);
+ /* Monitors aren't meant to send messages to us. */
+ if (bus_connection_is_monitor (connection))
+ {
+ sender = bus_connection_get_name (connection);
+
+ /* should never happen */
+ if (sender == NULL)
+ sender = "(unknown)";
+
+ if (dbus_message_is_signal (message,
+ DBUS_INTERFACE_LOCAL,
+ "Disconnected"))
+ {
+ bus_context_log (context, DBUS_SYSTEM_LOG_INFO,
+ "Monitoring connection %s closed.", sender);
+ bus_connection_disconnected (connection);
+ goto out;
+ }
+ else
+ {
+ /* Monitors are not allowed to send messages, because that
+ * probably indicates that the monitor is incorrectly replying
+ * to its eavesdropped messages, and we want the authors of
+ * such monitors to fix them.
+ */
+ bus_context_log (context, DBUS_SYSTEM_LOG_WARNING,
+ "Monitoring connection %s (%s) is not allowed "
+ "to send messages; closing it. Please fix the "
+ "monitor to not do that. "
+ "(message type=\"%s\" interface=\"%s\" "
+ "member=\"%s\" error name=\"%s\" "
+ "destination=\"%s\")",
+ sender, bus_connection_get_loginfo (connection),
+ dbus_message_type_to_string (
+ dbus_message_get_type (message)),
+ nonnull (dbus_message_get_interface (message),
+ "(unset)"),
+ nonnull (dbus_message_get_member (message),
+ "(unset)"),
+ nonnull (dbus_message_get_error_name (message),
+ "(unset)"),
+ nonnull (dbus_message_get_destination (message),
+ DBUS_SERVICE_DBUS));
+ dbus_connection_close (connection);
+ goto out;
+ }
+ }
+
service_name = dbus_message_get_destination (message);
#ifdef DBUS_ENABLE_VERBOSE_MODE
@@ -236,6 +321,10 @@ bus_dispatch (DBusConnection *connection,
{
/* DBusConnection also handles some of these automatically, we leave
* it to do so.
+ *
+ * FIXME: this means monitors won't get the opportunity to see
+ * non-signals with NULL destination, or their replies (which in
+ * practice are UnknownMethod errors)
*/
result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
goto out;
@@ -261,13 +350,30 @@ bus_dispatch (DBusConnection *connection,
BUS_SET_OOM (&error);
goto out;
}
+ }
+ else
+ {
+ /* For monitors' benefit: we don't want the sender to be able to
+ * trick the monitor by supplying a forged sender, and we also
+ * don't want the message to have no sender at all. */
+ if (!dbus_message_set_sender (message, ":not.active.yet"))
+ {
+ 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);
+ /* 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 (!bus_transaction_capture (transaction, connection, message))
+ {
+ BUS_SET_OOM (&error);
+ goto out;
}
if (service_name &&
@@ -347,14 +453,10 @@ bus_dispatch (DBusConnection *connection,
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))
+ /* Even if we disconnected it, pretend to send it any pending error
+ * messages so that monitors can observe them.
+ */
+ if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
{
bus_connection_send_oom_error (connection, message);
@@ -433,6 +535,8 @@ bus_dispatch_remove_connection (DBusConnection *connection)
#include <stdio.h>
+#include "stats.h"
+
/* 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.
@@ -1228,7 +1332,9 @@ check_get_connection_unix_process_id (BusContext *context,
dbus_bool_t retval;
DBusError error;
const char *base_service_name;
+#ifdef DBUS_UNIX
dbus_uint32_t pid;
+#endif
retval = FALSE;
dbus_error_init (&error);
@@ -1310,6 +1416,11 @@ check_get_connection_unix_process_id (BusContext *context,
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
defined(__linux__) || \
defined(__OpenBSD__)
+ /* In principle NetBSD should also be in that list, but
+ * its implementation of PID-passing doesn't work
+ * over a socketpair() as used in the debug-pipe transport.
+ * We test this functionality in a more realistic situation
+ * in test/dbus-daemon.c. */
warn_unexpected (connection, message, "not this error");
goto out;
@@ -1393,20 +1504,21 @@ check_get_connection_unix_process_id (BusContext *context,
* but the correct thing may include OOM errors.
*/
static dbus_bool_t
-check_add_match_all (BusContext *context,
- DBusConnection *connection)
+check_add_match (BusContext *context,
+ DBusConnection *connection,
+ const char *rule)
{
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);
+ _dbus_verbose ("check_add_match for connection %p, rule %s\n",
+ connection, rule);
message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
DBUS_PATH_DBUS,
@@ -1416,8 +1528,7 @@ check_add_match_all (BusContext *context,
if (message == NULL)
return TRUE;
- /* empty string match rule matches everything */
- if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &empty,
+ if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &rule,
DBUS_TYPE_INVALID))
{
dbus_message_unref (message);
@@ -1521,6 +1632,132 @@ check_add_match_all (BusContext *context,
return retval;
}
+#ifdef DBUS_ENABLE_STATS
+/* returns TRUE if the correct thing happens,
+ * but the correct thing may include OOM errors.
+ */
+static dbus_bool_t
+check_get_all_match_rules (BusContext *context,
+ DBusConnection *connection)
+{
+ DBusMessage *message;
+ dbus_bool_t retval;
+ dbus_uint32_t serial;
+ DBusError error;
+
+ retval = FALSE;
+ dbus_error_init (&error);
+ message = NULL;
+
+ _dbus_verbose ("check_get_all_match_rules for connection %p\n",
+ connection);
+
+ message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ BUS_INTERFACE_STATS,
+ "GetAllMatchRules");
+
+ if (message == NULL)
+ 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\n");
+
+ 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\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",
+ "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;
+}
+#endif
+
/* returns TRUE if the correct thing happens,
* but the correct thing may include OOM errors.
*/
@@ -1561,7 +1798,7 @@ check_hello_connection (BusContext *context)
}
else
{
- if (!check_add_match_all (context, connection))
+ if (!check_add_match (context, connection, ""))
return FALSE;
kill_client_connection (context, connection);
@@ -4516,7 +4753,7 @@ bus_dispatch_test_conf (const DBusString *test_data_dir,
if (!check_double_hello_message (context, foo))
_dbus_assert_not_reached ("double hello message failed");
- if (!check_add_match_all (context, foo))
+ if (!check_add_match (context, foo, ""))
_dbus_assert_not_reached ("AddMatch message failed");
bar = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
@@ -4531,7 +4768,7 @@ bus_dispatch_test_conf (const DBusString *test_data_dir,
if (!check_hello_message (context, bar))
_dbus_assert_not_reached ("hello message failed");
- if (!check_add_match_all (context, bar))
+ if (!check_add_match (context, bar, ""))
_dbus_assert_not_reached ("AddMatch message failed");
baz = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
@@ -4546,9 +4783,17 @@ bus_dispatch_test_conf (const DBusString *test_data_dir,
if (!check_hello_message (context, baz))
_dbus_assert_not_reached ("hello message failed");
- if (!check_add_match_all (context, baz))
+ if (!check_add_match (context, baz, ""))
+ _dbus_assert_not_reached ("AddMatch message failed");
+
+ if (!check_add_match (context, baz, "interface='com.example'"))
_dbus_assert_not_reached ("AddMatch message failed");
+#ifdef DBUS_ENABLE_STATS
+ if (!check_get_all_match_rules (context, baz))
+ _dbus_assert_not_reached ("GetAllMatchRules message failed");
+#endif
+
#ifdef DBUS_WIN_FIXME
_dbus_warn("TODO: testing of GetConnectionUnixUser message skipped for now\n");
_dbus_warn("TODO: testing of GetConnectionUnixProcessID message skipped for now\n");
@@ -4665,7 +4910,7 @@ bus_dispatch_test_conf_fail (const DBusString *test_data_dir,
if (!check_double_hello_message (context, foo))
_dbus_assert_not_reached ("double hello message failed");
- if (!check_add_match_all (context, foo))
+ if (!check_add_match (context, foo, ""))
_dbus_assert_not_reached ("AddMatch message failed");
/* this only tests the activation.c user check */
@@ -4745,7 +4990,7 @@ bus_dispatch_sha1_test (const DBusString *test_data_dir)
if (!check_hello_message (context, foo))
_dbus_assert_not_reached ("hello message failed");
- if (!check_add_match_all (context, foo))
+ if (!check_add_match (context, foo, ""))
_dbus_assert_not_reached ("addmatch message failed");
if (!check_no_leftovers (context))
@@ -4773,7 +5018,8 @@ bus_unix_fds_passing_test(const DBusString *test_data_dir)
DBusConnection *foo, *bar;
DBusError error;
DBusMessage *m;
- int one[2], two[2], x, y, z;
+ DBusSocket one[2], two[2];
+ int x, y, z;
char r;
dbus_error_init (&error);
@@ -4794,7 +5040,7 @@ bus_unix_fds_passing_test(const DBusString *test_data_dir)
if (!check_hello_message (context, foo))
_dbus_assert_not_reached ("hello message failed");
- if (!check_add_match_all (context, foo))
+ if (!check_add_match (context, foo, ""))
_dbus_assert_not_reached ("AddMatch message failed");
bar = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
@@ -4809,16 +5055,16 @@ bus_unix_fds_passing_test(const DBusString *test_data_dir)
if (!check_hello_message (context, bar))
_dbus_assert_not_reached ("hello message failed");
- if (!check_add_match_all (context, bar))
+ if (!check_add_match (context, bar, ""))
_dbus_assert_not_reached ("AddMatch message failed");
if (!(m = dbus_message_new_signal("/", "a.b.c", "d")))
_dbus_assert_not_reached ("could not alloc message");
- if (!(_dbus_full_duplex_pipe(one, one+1, TRUE, &error)))
+ if (!(_dbus_socketpair (one, one+1, TRUE, &error)))
_dbus_assert_not_reached("Failed to allocate pipe #1");
- if (!(_dbus_full_duplex_pipe(two, two+1, TRUE, &error)))
+ if (!(_dbus_socketpair (two, two+1, TRUE, &error)))
_dbus_assert_not_reached("Failed to allocate pipe #2");
if (!dbus_message_append_args(m,
@@ -4828,9 +5074,9 @@ bus_unix_fds_passing_test(const DBusString *test_data_dir)
DBUS_TYPE_INVALID))
_dbus_assert_not_reached("Failed to attach fds.");
- if (!_dbus_close(one[0], &error))
+ if (!_dbus_close_socket (one[0], &error))
_dbus_assert_not_reached("Failed to close pipe #1 ");
- if (!_dbus_close(two[0], &error))
+ if (!_dbus_close_socket (two[0], &error))
_dbus_assert_not_reached("Failed to close pipe #2 ");
if (!(dbus_connection_can_send_type(foo, DBUS_TYPE_UNIX_FD)))
@@ -4890,16 +5136,16 @@ bus_unix_fds_passing_test(const DBusString *test_data_dir)
if (!_dbus_close(z, &error))
_dbus_assert_not_reached("Failed to close pipe #2/other size 2nd fd ");
- if (read(one[1], &r, 1) != 1 || r != 'X')
+ if (read(one[1].fd, &r, 1) != 1 || r != 'X')
_dbus_assert_not_reached("Failed to read value from pipe.");
- if (read(two[1], &r, 1) != 1 || r != 'Y')
+ if (read(two[1].fd, &r, 1) != 1 || r != 'Y')
_dbus_assert_not_reached("Failed to read value from pipe.");
- if (read(two[1], &r, 1) != 1 || r != 'Z')
+ if (read(two[1].fd, &r, 1) != 1 || r != 'Z')
_dbus_assert_not_reached("Failed to read value from pipe.");
- if (!_dbus_close(one[1], &error))
+ if (!_dbus_close_socket (one[1], &error))
_dbus_assert_not_reached("Failed to close pipe #1 ");
- if (!_dbus_close(two[1], &error))
+ if (!_dbus_close_socket (two[1], &error))
_dbus_assert_not_reached("Failed to close pipe #2 ");
_dbus_verbose ("Disconnecting foo\n");
diff --git a/bus/driver.c b/bus/driver.c
index 888c7ca7..379a47ee 100644
--- a/bus/driver.c
+++ b/bus/driver.c
@@ -24,6 +24,7 @@
#include <config.h>
#include "activation.h"
+#include "apparmor.h"
#include "connection.h"
#include "driver.h"
#include "dispatch.h"
@@ -34,12 +35,39 @@
#include "utils.h"
#include <dbus/dbus-asv-util.h>
+#include <dbus/dbus-connection-internal.h>
#include <dbus/dbus-string.h>
#include <dbus/dbus-internals.h>
#include <dbus/dbus-message.h>
#include <dbus/dbus-marshal-recursive.h>
+#include <dbus/dbus-marshal-validate.h>
#include <string.h>
+static inline const char *
+nonnull (const char *maybe_null,
+ const char *if_null)
+{
+ return (maybe_null ? maybe_null : if_null);
+}
+
+static DBusConnection *
+bus_driver_get_owner_of_name (DBusConnection *connection,
+ const char *name)
+{
+ BusRegistry *registry;
+ BusService *serv;
+ DBusString str;
+
+ registry = bus_connection_get_registry (connection);
+ _dbus_string_init_const (&str, name);
+ serv = bus_registry_lookup (registry, &str);
+
+ if (serv == NULL)
+ return NULL;
+
+ return bus_service_get_primary_owners_connection (serv);
+}
+
static DBusConnection *
bus_driver_get_conn_helper (DBusConnection *connection,
DBusMessage *message,
@@ -47,11 +75,8 @@ bus_driver_get_conn_helper (DBusConnection *connection,
const char **name_p,
DBusError *error)
{
- const char *name;
- BusRegistry *registry;
- BusService *serv;
- DBusString str;
DBusConnection *conn;
+ const char *name;
if (!dbus_message_get_args (message, error,
DBUS_TYPE_STRING, &name,
@@ -61,11 +86,9 @@ bus_driver_get_conn_helper (DBusConnection *connection,
_dbus_assert (name != NULL);
_dbus_verbose ("asked for %s of connection %s\n", what_we_want, name);
- registry = bus_connection_get_registry (connection);
- _dbus_string_init_const (&str, name);
- serv = bus_registry_lookup (registry, &str);
+ conn = bus_driver_get_owner_of_name (connection, name);
- if (serv == NULL)
+ if (conn == NULL)
{
dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER,
"Could not get %s of name '%s': no such name",
@@ -73,15 +96,107 @@ bus_driver_get_conn_helper (DBusConnection *connection,
return NULL;
}
- conn = bus_service_get_primary_owners_connection (serv);
- _dbus_assert (conn != NULL);
-
if (name_p != NULL)
*name_p = name;
return conn;
}
+/*
+ * Log a security warning and set error unless the uid of the connection
+ * is either the uid of this process, or on Unix, uid 0 (root).
+ *
+ * This is intended to be a second line of defence after <deny> rules,
+ * to mitigate incorrect system bus security policy configuration files
+ * like the ones in CVE-2014-8148 and CVE-2014-8156, and (if present)
+ * LSM rules; so it doesn't need to be perfect, but as long as we have
+ * potentially dangerous functionality in the system bus, it does need
+ * to exist.
+ */
+static dbus_bool_t
+bus_driver_check_caller_is_privileged (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+#ifdef DBUS_UNIX
+ unsigned long uid;
+
+ if (!dbus_connection_get_unix_user (connection, &uid))
+ {
+ const char *method = dbus_message_get_member (message);
+
+ bus_context_log_and_set_error (bus_transaction_get_context (transaction),
+ DBUS_SYSTEM_LOG_SECURITY, error, DBUS_ERROR_ACCESS_DENIED,
+ "rejected attempt to call %s by connection %s (%s) with "
+ "unknown uid", method,
+ nonnull (bus_connection_get_name (connection), "(inactive)"),
+ bus_connection_get_loginfo (connection));
+ return FALSE;
+ }
+
+ /* I'm writing it in this slightly strange form so that it's more
+ * obvious that this security-sensitive code is correct.
+ */
+ if (_dbus_unix_user_is_process_owner (uid))
+ {
+ /* OK */
+ }
+ else if (uid == 0)
+ {
+ /* OK */
+ }
+ else
+ {
+ const char *method = dbus_message_get_member (message);
+
+ bus_context_log_and_set_error (bus_transaction_get_context (transaction),
+ DBUS_SYSTEM_LOG_SECURITY, error, DBUS_ERROR_ACCESS_DENIED,
+ "rejected attempt to call %s by connection %s (%s) with "
+ "uid %lu", method,
+ nonnull (bus_connection_get_name (connection), "(inactive)"),
+ bus_connection_get_loginfo (connection), uid);
+ return FALSE;
+ }
+
+ return TRUE;
+#elif defined(DBUS_WIN)
+ char *windows_sid = NULL;
+ dbus_bool_t ret = FALSE;
+
+ if (!dbus_connection_get_windows_user (connection, &windows_sid))
+ {
+ const char *method = dbus_message_get_member (message);
+
+ bus_context_log_and_set_error (bus_transaction_get_context (transaction),
+ DBUS_SYSTEM_LOG_SECURITY, error, DBUS_ERROR_ACCESS_DENIED,
+ "rejected attempt to call %s by unknown uid", method);
+ goto out;
+ }
+
+ if (!_dbus_windows_user_is_process_owner (windows_sid))
+ {
+ const char *method = dbus_message_get_member (message);
+
+ bus_context_log_and_set_error (bus_transaction_get_context (transaction),
+ DBUS_SYSTEM_LOG_SECURITY, error, DBUS_ERROR_ACCESS_DENIED,
+ "rejected attempt to call %s by uid %s", method, windows_sid);
+ goto out;
+ }
+
+ ret = TRUE;
+out:
+ dbus_free (windows_sid);
+ return ret;
+#else
+ /* make sure we fail closed in the hypothetical case that we are neither
+ * Unix nor Windows */
+ dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+ "please teach bus/driver.c how uids work on this platform");
+ return FALSE;
+#endif
+}
+
static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection,
DBusMessage *hello_message,
BusTransaction *transaction,
@@ -128,6 +243,9 @@ bus_driver_send_service_owner_changed (const char *service_name,
_dbus_assert (dbus_message_has_signature (message, "sss"));
+ if (!bus_transaction_capture (transaction, NULL, message))
+ goto oom;
+
retval = bus_dispatch_matches (transaction, NULL, NULL, message, error);
dbus_message_unref (message);
@@ -884,35 +1002,12 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection,
#ifdef DBUS_UNIX
{
/* UpdateActivationEnvironment is basically a recipe for privilege
- * escalation so let's be extra-careful: do not allow the sysadmin
- * to shoot themselves in the foot. */
- unsigned long uid;
-
- if (!dbus_connection_get_unix_user (connection, &uid))
- {
- bus_context_log (bus_transaction_get_context (transaction),
- DBUS_SYSTEM_LOG_SECURITY,
- "rejected attempt to call UpdateActivationEnvironment by "
- "unknown uid");
- dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
- "rejected attempt to call UpdateActivationEnvironment by "
- "unknown uid");
- return FALSE;
- }
-
- /* On the system bus, we could in principle allow uid 0 to call
- * UpdateActivationEnvironment; but they should know better anyway,
- * and our default system.conf has always forbidden it */
- if (!_dbus_unix_user_is_process_owner (uid))
- {
- bus_context_log (bus_transaction_get_context (transaction),
- DBUS_SYSTEM_LOG_SECURITY,
- "rejected attempt to call UpdateActivationEnvironment by uid %lu",
- uid);
- dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
- "rejected attempt to call UpdateActivationEnvironment");
- return FALSE;
- }
+ * escalation so let's be extra-careful: do not allow the sysadmin
+ * to shoot themselves in the foot.
+ */
+ if (!bus_driver_check_caller_is_privileged (connection, transaction,
+ message, error))
+ return FALSE;
}
#endif
@@ -1029,9 +1124,10 @@ bus_driver_handle_add_match (DBusConnection *connection,
DBusError *error)
{
BusMatchRule *rule;
- const char *text;
+ const char *text, *bustype;
DBusString str;
BusMatchmaker *matchmaker;
+ BusContext *context;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -1064,6 +1160,12 @@ bus_driver_handle_add_match (DBusConnection *connection,
if (rule == NULL)
goto failed;
+ context = bus_transaction_get_context (transaction);
+ bustype = context ? bus_context_get_type (context) : NULL;
+ if (bus_match_rule_get_client_is_eavesdropping (rule) &&
+ !bus_apparmor_allows_eavesdropping (connection, bustype, error))
+ goto failed;
+
matchmaker = bus_connection_get_matchmaker (connection);
if (!bus_matchmaker_add_rule (matchmaker, rule))
@@ -1567,6 +1669,7 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
DBusMessageIter reply_iter;
DBusMessageIter array_iter;
unsigned long ulong_val;
+ char *s;
const char *service;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -1601,6 +1704,45 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
goto oom;
}
+ if (dbus_connection_get_windows_user (conn, &s))
+ {
+ DBusString str;
+ dbus_bool_t result;
+
+ if (s == NULL)
+ goto oom;
+
+ _dbus_string_init_const (&str, s);
+ result = _dbus_validate_utf8 (&str, 0, _dbus_string_get_length (&str));
+ _dbus_string_free (&str);
+ if (result)
+ {
+ if (!_dbus_asv_add_string (&array_iter, "WindowsSID", s))
+ {
+ dbus_free (s);
+ goto oom;
+ }
+ }
+ dbus_free (s);
+ }
+
+ if (_dbus_connection_get_linux_security_label (conn, &s))
+ {
+ if (s == NULL)
+ goto oom;
+
+ /* use the GVariant bytestring convention for strings of unknown
+ * encoding: include the \0 in the payload, for zero-copy reading */
+ if (!_dbus_asv_add_byte_array (&array_iter, "LinuxSecurityLabel",
+ s, strlen (s) + 1))
+ {
+ dbus_free (s);
+ goto oom;
+ }
+
+ dbus_free (s);
+ }
+
if (!_dbus_asv_close (&reply_iter, &array_iter))
goto oom;
@@ -1669,6 +1811,72 @@ bus_driver_handle_reload_config (DBusConnection *connection,
return FALSE;
}
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+static dbus_bool_t
+bus_driver_handle_enable_verbose (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ DBusMessage *reply = NULL;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ goto oom;
+
+ if (! bus_transaction_send_from_driver (transaction, connection, reply))
+ goto oom;
+
+ _dbus_set_verbose(TRUE);
+
+ dbus_message_unref (reply);
+ return TRUE;
+
+ oom:
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ BUS_SET_OOM (error);
+
+ if (reply)
+ dbus_message_unref (reply);
+ return FALSE;
+}
+
+static dbus_bool_t
+bus_driver_handle_disable_verbose (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ DBusMessage *reply = NULL;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ goto oom;
+
+ if (! bus_transaction_send_from_driver (transaction, connection, reply))
+ goto oom;
+
+ _dbus_set_verbose(FALSE);
+
+ dbus_message_unref (reply);
+ return TRUE;
+
+ oom:
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ BUS_SET_OOM (error);
+
+ if (reply)
+ dbus_message_unref (reply);
+ return FALSE;
+}
+#endif
+
static dbus_bool_t
bus_driver_handle_get_id (DBusConnection *connection,
BusTransaction *transaction,
@@ -1724,6 +1932,124 @@ bus_driver_handle_get_id (DBusConnection *connection,
return FALSE;
}
+static dbus_bool_t
+bus_driver_handle_become_monitor (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ char **match_rules = NULL;
+ const char *bustype;
+ BusContext *context;
+ BusMatchRule *rule;
+ DBusList *rules = NULL;
+ DBusList *iter;
+ DBusString str;
+ int i;
+ int n_match_rules;
+ dbus_uint32_t flags;
+ dbus_bool_t ret = FALSE;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ if (!bus_driver_check_message_is_for_us (message, error))
+ goto out;
+
+ context = bus_transaction_get_context (transaction);
+ bustype = context ? bus_context_get_type (context) : NULL;
+ if (!bus_apparmor_allows_eavesdropping (connection, bustype, error))
+ goto out;
+
+ if (!bus_driver_check_caller_is_privileged (connection, transaction,
+ message, error))
+ goto out;
+
+ if (!dbus_message_get_args (message, error,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &match_rules, &n_match_rules,
+ DBUS_TYPE_UINT32, &flags,
+ DBUS_TYPE_INVALID))
+ goto out;
+
+ if (flags != 0)
+ {
+ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+ "BecomeMonitor does not support any flags yet");
+ goto out;
+ }
+
+ /* Special case: a zero-length array becomes [""] */
+ if (n_match_rules == 0)
+ {
+ match_rules = dbus_malloc (2 * sizeof (char *));
+
+ if (match_rules == NULL)
+ {
+ BUS_SET_OOM (error);
+ goto out;
+ }
+
+ match_rules[0] = _dbus_strdup ("");
+
+ if (match_rules[0] == NULL)
+ {
+ BUS_SET_OOM (error);
+ goto out;
+ }
+
+ match_rules[1] = NULL;
+ n_match_rules = 1;
+ }
+
+ for (i = 0; i < n_match_rules; i++)
+ {
+ _dbus_string_init_const (&str, match_rules[i]);
+ rule = bus_match_rule_parse (connection, &str, error);
+
+ if (rule == NULL)
+ {
+ BUS_SET_OOM (error);
+ goto out;
+ }
+
+ /* monitors always eavesdrop */
+ bus_match_rule_set_client_is_eavesdropping (rule, TRUE);
+
+ if (!_dbus_list_append (&rules, rule))
+ {
+ BUS_SET_OOM (error);
+ bus_match_rule_unref (rule);
+ goto out;
+ }
+ }
+
+ /* Send the ack before we remove the rule, since the ack is undone
+ * on transaction cancel, but becoming a monitor isn't.
+ */
+ if (!send_ack_reply (connection, transaction, message, error))
+ goto out;
+
+ if (!bus_connection_be_monitor (connection, transaction, &rules, error))
+ goto out;
+
+ ret = TRUE;
+
+out:
+ if (ret)
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+ else
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+
+ for (iter = _dbus_list_get_first_link (&rules);
+ iter != NULL;
+ iter = _dbus_list_get_next_link (&rules, iter))
+ bus_match_rule_unref (iter->data);
+
+ _dbus_list_clear (&rules);
+
+ dbus_free_string_array (match_rules);
+ return ret;
+}
+
typedef struct
{
const char *name;
@@ -1825,10 +2151,24 @@ static const MessageHandler introspectable_message_handlers[] = {
{ NULL, NULL, NULL, NULL }
};
+static const MessageHandler monitoring_message_handlers[] = {
+ { "BecomeMonitor", "asu", "", bus_driver_handle_become_monitor },
+ { NULL, NULL, NULL, NULL }
+};
+
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+static const MessageHandler verbose_message_handlers[] = {
+ { "EnableVerbose", "", "", bus_driver_handle_enable_verbose},
+ { "DisableVerbose", "", "", bus_driver_handle_disable_verbose},
+ { NULL, NULL, NULL, NULL }
+};
+#endif
+
#ifdef DBUS_ENABLE_STATS
static const MessageHandler stats_message_handlers[] = {
{ "GetStats", "", "a{sv}", bus_stats_handle_get_stats },
{ "GetConnectionStats", "s", "a{sv}", bus_stats_handle_get_connection_stats },
+ { "GetAllMatchRules", "", "a{sas}", bus_stats_handle_get_all_match_rules },
{ NULL, NULL, NULL, NULL }
};
#endif
@@ -1855,6 +2195,10 @@ static InterfaceHandler interface_handlers[] = {
" <arg type=\"s\"/>\n"
" </signal>\n" },
{ DBUS_INTERFACE_INTROSPECTABLE, introspectable_message_handlers, NULL },
+ { DBUS_INTERFACE_MONITORING, monitoring_message_handlers, NULL },
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+ { DBUS_INTERFACE_VERBOSE, verbose_message_handlers, NULL },
+#endif
#ifdef DBUS_ENABLE_STATS
{ BUS_INTERFACE_STATS, stats_message_handlers, NULL },
#endif
@@ -2053,8 +2397,26 @@ bus_driver_handle_message (DBusConnection *connection,
if (dbus_message_is_signal (message, "org.freedesktop.systemd1.Activator", "ActivationFailure"))
{
BusContext *context;
+ DBusConnection *systemd;
context = bus_connection_get_context (connection);
+ systemd = bus_driver_get_owner_of_name (connection,
+ "org.freedesktop.systemd1");
+
+ if (systemd != connection)
+ {
+ const char *attacker;
+
+ attacker = bus_connection_get_name (connection);
+ bus_context_log (context, DBUS_SYSTEM_LOG_SECURITY,
+ "Ignoring forged ActivationFailure message from "
+ "connection %s (%s)",
+ attacker ? attacker : "(unauthenticated)",
+ bus_connection_get_loginfo (connection));
+ /* ignore it */
+ return TRUE;
+ }
+
return dbus_activation_systemd_failure(bus_context_get_activation(context), message);
}
diff --git a/bus/example-session-disable-stats.conf.in b/bus/example-session-disable-stats.conf.in
new file mode 100644
index 00000000..2863ef0f
--- /dev/null
+++ b/bus/example-session-disable-stats.conf.in
@@ -0,0 +1,15 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+
+ <!-- If the Stats interface was enabled at compile-time, users can use it on
+ the session bus by default. Systems providing isolation of processes
+ with LSMs might want to restrict this. This can be achieved by copying
+ this file in @EXPANDED_SYSCONFDIR@/dbus-1/session.d/ -->
+
+ <policy context="default">
+ <deny send_destination="org.freedesktop.DBus"
+ send_interface="org.freedesktop.DBus.Debug.Stats"/>
+ </policy>
+
+</busconfig>
diff --git a/bus/example-system-enable-stats.conf.in b/bus/example-system-enable-stats.conf.in
new file mode 100644
index 00000000..a85aa835
--- /dev/null
+++ b/bus/example-system-enable-stats.conf.in
@@ -0,0 +1,15 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+
+ <!-- If the Stats interface was enabled at compile-time, only root may use it.
+ Replace USERNAME and copy this file in @EXPANDED_SYSCONFDIR@/dbus-1/system.d/
+ if you want to enable other privileged users to view statistics and
+ debug info -->
+
+ <policy user="USERNAME">
+ <allow send_destination="org.freedesktop.DBus"
+ send_interface="org.freedesktop.DBus.Debug.Stats"/>
+ </policy>
+
+</busconfig>
diff --git a/bus/legacy-config/session.conf.in b/bus/legacy-config/session.conf.in
new file mode 100644
index 00000000..aaea9104
--- /dev/null
+++ b/bus/legacy-config/session.conf.in
@@ -0,0 +1,20 @@
+<!--
+This configuration file is no longer required and may be removed.
+
+In older versions of dbus, this file defined the behaviour of the well-known
+session bus. That behaviour is now determined by
+@DBUS_DATADIR@/dbus-1/session.conf, which should not be edited.
+
+For local configuration changes, create a file
+@DBUS_SYSCONFDIR@/dbus-1/session-local.conf or files matching
+@DBUS_SYSCONFDIR@/dbus-1/session.d/*.conf, with a <busconfig>
+element containing configuration directives. These directives can
+override D-Bus or OS defaults.
+
+For upstream or distribution-wide defaults that can be overridden
+by a local sysadmin, create files matching
+@DBUS_DATADIR@/dbus-1/session.d/*.conf instead.
+-->
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig></busconfig>
diff --git a/bus/legacy-config/system.conf.in b/bus/legacy-config/system.conf.in
new file mode 100644
index 00000000..84ed2967
--- /dev/null
+++ b/bus/legacy-config/system.conf.in
@@ -0,0 +1,20 @@
+<!--
+This configuration file is no longer required and may be removed.
+
+In older versions of dbus, this file defined the behaviour of the well-known
+system bus. That behaviour is now determined by
+@DBUS_DATADIR@/dbus-1/system.conf, which should not be edited.
+
+For local configuration changes, create a file
+@DBUS_SYSCONFDIR@/dbus-1/system-local.conf or files matching
+@DBUS_SYSCONFDIR@/dbus-1/system.d/*.conf, with a <busconfig>
+element containing configuration directives. These directives can
+override D-Bus or OS defaults.
+
+For upstream or distribution-wide defaults that can be overridden
+by a local sysadmin, create files matching
+@DBUS_DATADIR@/dbus-1/system.d/*.conf instead.
+-->
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig></busconfig>
diff --git a/bus/main.c b/bus/main.c
index e060baa8..cb08055d 100644
--- a/bus/main.c
+++ b/bus/main.c
@@ -39,12 +39,15 @@
#include <unistd.h> /* for write() and STDERR_FILENO */
#endif
#include "selinux.h"
+#include "apparmor.h"
static BusContext *context;
#ifdef DBUS_UNIX
-static int reload_pipe[2];
+/* Despite its name and its unidirectional nature, this is actually
+ * a socket pair. */
+static DBusSocket reload_pipe[2];
#define RELOAD_READ_END 0
#define RELOAD_WRITE_END 1
@@ -67,7 +70,7 @@ signal_handler (int sig)
char action[2] = { ACTION_RELOAD, '\0' };
_dbus_string_init_const (&str, action);
- if ((reload_pipe[RELOAD_WRITE_END] > 0) &&
+ if ((reload_pipe[RELOAD_WRITE_END].fd > 0) &&
!_dbus_write_socket (reload_pipe[RELOAD_WRITE_END], &str, 0, 1))
{
/* If we receive SIGHUP often enough to fill the pipe buffer (4096
@@ -86,7 +89,8 @@ signal_handler (int sig)
static const char message[] =
"Unable to write to reload pipe - buffer full?\n";
- if (write (STDERR_FILENO, message, strlen (message)) != strlen (message))
+ if (write (STDERR_FILENO, message, strlen (message)) !=
+ (ssize_t) strlen (message))
{
/* ignore failure to write out a warning */
}
@@ -99,7 +103,7 @@ signal_handler (int sig)
DBusString str;
char action[2] = { ACTION_QUIT, '\0' };
_dbus_string_init_const (&str, action);
- if ((reload_pipe[RELOAD_WRITE_END] < 0) ||
+ if ((reload_pipe[RELOAD_WRITE_END].fd < 0) ||
!_dbus_write_socket (reload_pipe[RELOAD_WRITE_END], &str, 0, 1))
{
/* If we can't write to the socket, dying seems a more
@@ -110,7 +114,8 @@ signal_handler (int sig)
"Unable to write termination signal to pipe - buffer full?\n"
"Will exit instead.\n";
- if (write (STDERR_FILENO, message, strlen (message)) != strlen (message))
+ if (write (STDERR_FILENO, message, strlen (message)) !=
+ (ssize_t) strlen (message))
{
/* ignore failure to write out a warning */
}
@@ -243,7 +248,7 @@ handle_reload_watch (DBusWatch *watch,
while (!_dbus_string_init (&str))
_dbus_wait_for_memory ();
- if ((reload_pipe[RELOAD_READ_END] > 0) &&
+ if ((reload_pipe[RELOAD_READ_END].fd > 0) &&
_dbus_read_socket (reload_pipe[RELOAD_READ_END], &str, 1) != 1)
{
_dbus_warn ("Couldn't read from reload pipe.\n");
@@ -310,8 +315,8 @@ setup_reload_pipe (DBusLoop *loop)
dbus_error_init (&error);
- if (!_dbus_full_duplex_pipe (&reload_pipe[0], &reload_pipe[1],
- TRUE, &error))
+ if (!_dbus_socketpair (&reload_pipe[0], &reload_pipe[1],
+ TRUE, &error))
{
_dbus_warn ("Unable to create reload pipe: %s\n",
error.message);
@@ -319,9 +324,9 @@ setup_reload_pipe (DBusLoop *loop)
exit (1);
}
- watch = _dbus_watch_new (reload_pipe[RELOAD_READ_END],
- DBUS_WATCH_READABLE, TRUE,
- handle_reload_watch, NULL, NULL);
+ watch = _dbus_watch_new (_dbus_socket_get_pollable (reload_pipe[RELOAD_READ_END]),
+ DBUS_WATCH_READABLE, TRUE,
+ handle_reload_watch, NULL, NULL);
if (watch == NULL)
{
@@ -350,10 +355,10 @@ close_reload_pipe (DBusWatch **watch)
*watch = NULL;
_dbus_close_socket (reload_pipe[RELOAD_READ_END], NULL);
- reload_pipe[RELOAD_READ_END] = -1;
+ _dbus_socket_invalidate (&reload_pipe[RELOAD_READ_END]);
_dbus_close_socket (reload_pipe[RELOAD_WRITE_END], NULL);
- reload_pipe[RELOAD_WRITE_END] = -1;
+ _dbus_socket_invalidate (&reload_pipe[RELOAD_WRITE_END]);
}
#endif /* DBUS_UNIX */
@@ -614,6 +619,12 @@ main (int argc, char **argv)
exit (1);
}
+ if (!bus_apparmor_pre_init ())
+ {
+ _dbus_warn ("AppArmor pre-initialization failed: out of memory\n");
+ exit (1);
+ }
+
dbus_error_init (&error);
context = bus_context_new (&config_file, flags,
&print_addr_pipe, &print_pid_pipe,
@@ -649,6 +660,7 @@ main (int argc, char **argv)
bus_context_shutdown (context);
bus_context_unref (context);
bus_selinux_shutdown ();
+ bus_apparmor_shutdown ();
return 0;
}
diff --git a/bus/selinux.c b/bus/selinux.c
index 99994ca9..2b8e5db2 100644
--- a/bus/selinux.c
+++ b/bus/selinux.c
@@ -157,12 +157,14 @@ log_callback (const char *fmt, ...)
vsnprintf(buf, sizeof(buf), fmt, ap);
audit_log_user_avc_message(audit_fd, AUDIT_USER_AVC, buf, NULL, NULL,
NULL, getuid());
- return;
+ goto out;
}
}
#endif /* HAVE_LIBAUDIT */
vsyslog (LOG_USER | LOG_INFO, fmt, ap);
+
+out:
va_end(ap);
}
diff --git a/bus/services.c b/bus/services.c
index 584485b1..6a4c8848 100644
--- a/bus/services.c
+++ b/bus/services.c
@@ -36,6 +36,7 @@
#include "policy.h"
#include "bus.h"
#include "selinux.h"
+#include "apparmor.h"
struct BusService
{
@@ -75,6 +76,7 @@ bus_registry_new (BusContext *context)
{
BusRegistry *registry;
+ _dbus_assert (context);
registry = dbus_new0 (BusRegistry, 1);
if (registry == NULL)
return NULL;
@@ -458,6 +460,11 @@ bus_registry_acquire_service (BusRegistry *registry,
_dbus_string_get_const_data (service_name));
goto out;
}
+
+ if (!bus_apparmor_allows_acquire_service (connection,
+ bus_context_get_type (registry->context),
+ _dbus_string_get_const_data (service_name), error))
+ goto out;
if (!bus_client_policy_check_can_own (policy, service_name))
{
diff --git a/bus/session.conf.in b/bus/session.conf.in
index e78c1d33..97e1f673 100644
--- a/bus/session.conf.in
+++ b/bus/session.conf.in
@@ -35,13 +35,18 @@
<allow own="*"/>
</policy>
+ <!-- Include legacy configuration location -->
+ <include ignore_missing="yes">@DBUS_SYSCONFDIR@/dbus-1/session.conf</include>
+
<!-- Config files are placed here that among other things,
further restrict the above policy for specific services. -->
<includedir>session.d</includedir>
+ <includedir>@DBUS_SYSCONFDIR@/dbus-1/session.d</includedir>
+
<!-- This is included last so local configuration can override what's
in this standard file -->
- <include ignore_missing="yes">session-local.conf</include>
+ <include ignore_missing="yes">@DBUS_SYSCONFDIR@/dbus-1/session-local.conf</include>
<include if_selinux_enabled="yes" selinux_root_relative="yes">contexts/dbus_contexts</include>
diff --git a/bus/signals.c b/bus/signals.c
index 4c500c67..e8def9f7 100644
--- a/bus/signals.c
+++ b/bus/signals.c
@@ -22,6 +22,9 @@
*/
#include <config.h>
+
+#include <string.h>
+
#include "signals.h"
#include "services.h"
#include "utils.h"
@@ -118,10 +121,46 @@ bus_match_rule_unref (BusMatchRule *rule)
}
}
-#ifdef DBUS_ENABLE_VERBOSE_MODE
-/* Note this function does not do escaping, so it's only
- * good for debug spew at the moment
- */
+#if defined(DBUS_ENABLE_VERBOSE_MODE) || defined(DBUS_ENABLE_STATS)
+static dbus_bool_t
+append_key_and_escaped_value (DBusString *str, const char *token, const char *value)
+{
+ const char *p = value;
+
+ if (!_dbus_string_append_printf (str, "%s='", token))
+ return FALSE;
+
+ while (*p != '\0')
+ {
+ const char *next = strchr (p, '\'');
+
+ if (next)
+ {
+ if (!_dbus_string_append_printf (str, "%.*s", (int) (next - p), p))
+ return FALSE;
+ /* Horrible escape sequence: single quote cannot be escaped inside
+ * a single quoted string. So we close the single quote, escape the
+ * single quote, and reopen a single quote.
+ */
+ if (!_dbus_string_append_printf (str, "'\\''"))
+ return FALSE;
+ p = next + 1;
+ }
+ else
+ {
+ if (!_dbus_string_append_printf (str, "%s", p))
+ return FALSE;
+ break;
+ }
+ }
+
+ if (!_dbus_string_append_byte (str, '\''))
+ return FALSE;
+
+ return TRUE;
+}
+
+/* returns NULL if no memory */
static char*
match_rule_to_string (BusMatchRule *rule)
{
@@ -130,15 +169,12 @@ match_rule_to_string (BusMatchRule *rule)
if (!_dbus_string_init (&str))
{
- char *s;
- while ((s = _dbus_strdup ("nomem")) == NULL)
- ; /* only OK for debug spew... */
- return s;
+ return NULL;
}
if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
{
- if (!_dbus_string_append_printf (&str, "type='%s'",
+ if (!append_key_and_escaped_value (&str, "type",
dbus_message_type_to_string (rule->message_type)))
goto nomem;
}
@@ -151,7 +187,7 @@ match_rule_to_string (BusMatchRule *rule)
goto nomem;
}
- if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
+ if (!append_key_and_escaped_value (&str, "interface", rule->interface))
goto nomem;
}
@@ -163,7 +199,7 @@ match_rule_to_string (BusMatchRule *rule)
goto nomem;
}
- if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
+ if (!append_key_and_escaped_value (&str, "member", rule->member))
goto nomem;
}
@@ -175,7 +211,7 @@ match_rule_to_string (BusMatchRule *rule)
goto nomem;
}
- if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
+ if (!append_key_and_escaped_value (&str, "path", rule->path))
goto nomem;
}
@@ -187,7 +223,7 @@ match_rule_to_string (BusMatchRule *rule)
goto nomem;
}
- if (!_dbus_string_append_printf (&str, "path_namespace='%s'", rule->path))
+ if (!append_key_and_escaped_value (&str, "path_namespace", rule->path))
goto nomem;
}
@@ -199,7 +235,7 @@ match_rule_to_string (BusMatchRule *rule)
goto nomem;
}
- if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
+ if (!append_key_and_escaped_value (&str, "sender", rule->sender))
goto nomem;
}
@@ -211,7 +247,7 @@ match_rule_to_string (BusMatchRule *rule)
goto nomem;
}
- if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
+ if (!append_key_and_escaped_value (&str, "destination", rule->destination))
goto nomem;
}
@@ -223,7 +259,7 @@ match_rule_to_string (BusMatchRule *rule)
goto nomem;
}
- if (!_dbus_string_append_printf (&str, "eavesdrop='%s'",
+ if (!append_key_and_escaped_value (&str, "eavesdrop",
(rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING) ?
"true" : "false"))
goto nomem;
@@ -252,11 +288,12 @@ match_rule_to_string (BusMatchRule *rule)
is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
if (!_dbus_string_append_printf (&str,
- "arg%d%s='%s'",
+ "arg%d%s",
i,
is_path ? "path" :
- is_namespace ? "namespace" : "",
- rule->args[i]))
+ is_namespace ? "namespace" : ""))
+ goto nomem;
+ if (!append_key_and_escaped_value (&str, "", rule->args[i]))
goto nomem;
}
@@ -272,14 +309,9 @@ match_rule_to_string (BusMatchRule *rule)
nomem:
_dbus_string_free (&str);
- {
- char *s;
- while ((s = _dbus_strdup ("nomem")) == NULL)
- ; /* only OK for debug spew... */
- return s;
- }
+ return NULL;
}
-#endif /* DBUS_ENABLE_VERBOSE_MODE */
+#endif /* defined(DBUS_ENABLE_VERBOSE_MODE) || defined(DBUS_ENABLE_STATS) */
dbus_bool_t
bus_match_rule_set_message_type (BusMatchRule *rule,
@@ -379,6 +411,15 @@ bus_match_rule_set_client_is_eavesdropping (BusMatchRule *rule,
}
dbus_bool_t
+bus_match_rule_get_client_is_eavesdropping (BusMatchRule *rule)
+{
+ if (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+dbus_bool_t
bus_match_rule_set_path (BusMatchRule *rule,
const char *path,
dbus_bool_t is_namespace)
@@ -807,7 +848,8 @@ bus_match_rule_parse_arg_match (BusMatchRule *rule,
if (end != length)
{
- if ((end + strlen ("path")) == length &&
+ int len1 = strlen ("path");
+ if ((end + len1) == length &&
_dbus_string_ends_with_c_str (&key_str, "path"))
{
is_path = TRUE;
@@ -1141,6 +1183,74 @@ struct BusMatchmaker
RulePool rules_by_type[DBUS_NUM_MESSAGE_TYPES];
};
+#ifdef DBUS_ENABLE_STATS
+dbus_bool_t
+bus_match_rule_dump (BusMatchmaker *matchmaker,
+ DBusConnection *conn_filter,
+ DBusMessageIter *arr_iter)
+{
+ int i;
+
+ for (i = 0 ; i < DBUS_NUM_MESSAGE_TYPES ; i++)
+ {
+ DBusHashIter iter;
+ DBusList **list;
+ DBusList *link;
+
+ _dbus_hash_iter_init (matchmaker->rules_by_type[i].rules_by_iface, &iter);
+ while (_dbus_hash_iter_next (&iter))
+ {
+ list = _dbus_hash_iter_get_value (&iter);
+ for (link = _dbus_list_get_first_link (list);
+ link != NULL;
+ link = _dbus_list_get_next_link (list, link))
+ {
+ BusMatchRule *rule = link->data;
+
+ if (rule->matches_go_to == conn_filter)
+ {
+ char *s = match_rule_to_string (rule);
+
+ if (s == NULL)
+ return FALSE;
+
+ if (!dbus_message_iter_append_basic (arr_iter, DBUS_TYPE_STRING, &s))
+ {
+ dbus_free (s);
+ return FALSE;
+ }
+ dbus_free (s);
+ }
+ }
+ }
+ list = &matchmaker->rules_by_type[i].rules_without_iface;
+ for (link = _dbus_list_get_first_link (list);
+ link != NULL;
+ link = _dbus_list_get_next_link (list, link))
+ {
+ BusMatchRule *rule = link->data;
+
+ if (rule->matches_go_to == conn_filter)
+ {
+ char *s = match_rule_to_string (rule);
+
+ if (s == NULL)
+ return FALSE;
+
+ if (!dbus_message_iter_append_basic (arr_iter, DBUS_TYPE_STRING, &s))
+ {
+ dbus_free (s);
+ return FALSE;
+ }
+ dbus_free (s);
+ }
+ }
+ }
+
+ return TRUE;
+}
+#endif
+
static void
rule_list_free (DBusList **rules)
{
@@ -1359,7 +1469,7 @@ bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
char *s = match_rule_to_string (rule);
_dbus_verbose ("Added match rule %s to connection %p\n",
- s, rule->matches_go_to);
+ s ? s : "nomem", rule->matches_go_to);
dbus_free (s);
}
#endif
@@ -1452,7 +1562,7 @@ bus_matchmaker_remove_rule_link (DBusList **rules,
char *s = match_rule_to_string (rule);
_dbus_verbose ("Removed match rule %s for connection %p\n",
- s, rule->matches_go_to);
+ s ? s : "nomem", rule->matches_go_to);
dbus_free (s);
}
#endif
@@ -1489,7 +1599,7 @@ bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
char *s = match_rule_to_string (rule);
_dbus_verbose ("Removed match rule %s for connection %p\n",
- s, rule->matches_go_to);
+ s ? s : "nomem", rule->matches_go_to);
dbus_free (s);
}
#endif
@@ -1966,7 +2076,7 @@ get_recipients_from_list (DBusList **rules,
char *s = match_rule_to_string (rule);
_dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
- s, rule->matches_go_to);
+ s ? s : "nomem", rule->matches_go_to);
dbus_free (s);
}
#endif
@@ -2239,7 +2349,7 @@ test_parsing (void *data)
rule = check_parse (TRUE, "arg7path='/foo'");
if (rule != NULL)
{
- _dbus_assert (rule->flags = BUS_MATCH_ARGS);
+ _dbus_assert (rule->flags == BUS_MATCH_ARGS);
_dbus_assert (rule->args != NULL);
_dbus_assert (rule->args_len == 8);
_dbus_assert (rule->args[7] != NULL);
@@ -2401,7 +2511,12 @@ static struct {
{ "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" },
{ "arg3='fool'", "arg3='fool'" },
{ "arg0namespace='fool'", "arg0namespace='fool'" },
- { "member='food'", "member='food'" }
+ { "member='food'", "member='food'" },
+ { "member=escape", "member='escape'" },
+ { "member=icecream", "member=ice'cream'" },
+ { "arg0='comma,type=comma',type=signal", "type=signal,arg0='comma,type=comma'" },
+ { "arg0=escap\\e", "arg0='escap\\e'" },
+ { "arg0=Time: 8 o\\'clock", "arg0='Time: 8 o'\\''clock'" },
};
static void
@@ -2414,6 +2529,8 @@ test_equality (void)
{
BusMatchRule *first;
BusMatchRule *second;
+ char *first_str, *second_str;
+ BusMatchRule *first_reparsed, *second_reparsed;
int j;
first = check_parse (TRUE, equality_tests[i].first);
@@ -2429,6 +2546,21 @@ test_equality (void)
exit (1);
}
+ /* Check match_rule_to_string */
+ first_str = match_rule_to_string (first);
+ _dbus_assert (first_str != NULL);
+ second_str = match_rule_to_string (second);
+ _dbus_assert (second_str != NULL);
+ _dbus_assert (strcmp (first_str, second_str) == 0);
+ first_reparsed = check_parse (TRUE, first_str);
+ second_reparsed = check_parse (TRUE, second_str);
+ _dbus_assert (match_rule_equal (first, first_reparsed));
+ _dbus_assert (match_rule_equal (second, second_reparsed));
+ bus_match_rule_unref (first_reparsed);
+ bus_match_rule_unref (second_reparsed);
+ dbus_free (first_str);
+ dbus_free (second_str);
+
bus_match_rule_unref (second);
/* Check that the rule is not equal to any of the
diff --git a/bus/signals.h b/bus/signals.h
index a71d2e45..0edfb07e 100644
--- a/bus/signals.h
+++ b/bus/signals.h
@@ -73,10 +73,18 @@ dbus_bool_t bus_match_rule_set_arg (BusMatchRule *rule,
void bus_match_rule_set_client_is_eavesdropping (BusMatchRule *rule,
dbus_bool_t is_eavesdropping);
+dbus_bool_t bus_match_rule_get_client_is_eavesdropping (BusMatchRule *rule);
+
BusMatchRule* bus_match_rule_parse (DBusConnection *matches_go_to,
const DBusString *rule_text,
DBusError *error);
+#ifdef DBUS_ENABLE_STATS
+dbus_bool_t bus_match_rule_dump (BusMatchmaker *matchmaker,
+ DBusConnection *conn_filter,
+ DBusMessageIter *arr_iter);
+#endif
+
BusMatchmaker* bus_matchmaker_new (void);
BusMatchmaker* bus_matchmaker_ref (BusMatchmaker *matchmaker);
void bus_matchmaker_unref (BusMatchmaker *matchmaker);
diff --git a/bus/stats.c b/bus/stats.c
index 20321e5e..dace0e29 100644
--- a/bus/stats.c
+++ b/bus/stats.c
@@ -31,6 +31,7 @@
#include "connection.h"
#include "driver.h"
#include "services.h"
+#include "signals.h"
#include "utils.h"
#ifdef DBUS_ENABLE_STATS
@@ -224,4 +225,120 @@ oom:
return FALSE;
}
+
+dbus_bool_t
+bus_stats_handle_get_all_match_rules (DBusConnection *caller_connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ BusContext *context;
+ DBusString bus_name_str;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter, hash_iter, entry_iter, arr_iter;
+ BusRegistry *registry;
+ char **services = NULL;
+ int services_len;
+ DBusConnection *conn_filter = NULL;
+ BusMatchmaker *matchmaker;
+ int i;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ registry = bus_connection_get_registry (caller_connection);
+ context = bus_transaction_get_context (transaction);
+ matchmaker = bus_context_get_matchmaker (context);
+
+ if (!bus_registry_list_services (registry, &services, &services_len))
+ return FALSE;
+
+ 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, "{sas}",
+ &hash_iter))
+ goto oom;
+
+ for (i = 0 ; i < services_len ; i++)
+ {
+ BusService *service;
+
+ /* To avoid duplicate entries, only look for unique names */
+ if (services[i][0] != ':')
+ continue;
+
+ _dbus_string_init_const (&bus_name_str, services[i]);
+ service = bus_registry_lookup (registry, &bus_name_str);
+ _dbus_assert (service != NULL);
+
+ conn_filter = bus_service_get_primary_owners_connection (service);
+ _dbus_assert (conn_filter != NULL);
+
+ if (!dbus_message_iter_open_container (&hash_iter, DBUS_TYPE_DICT_ENTRY, NULL,
+ &entry_iter))
+ {
+ dbus_message_iter_abandon_container (&iter, &hash_iter);
+ goto oom;
+ }
+
+ if (!dbus_message_iter_append_basic (&entry_iter, DBUS_TYPE_STRING, &services[i]))
+ {
+ dbus_message_iter_abandon_container (&hash_iter, &entry_iter);
+ dbus_message_iter_abandon_container (&iter, &hash_iter);
+ goto oom;
+ }
+
+ if (!dbus_message_iter_open_container (&entry_iter, DBUS_TYPE_ARRAY, "s",
+ &arr_iter))
+ {
+ dbus_message_iter_abandon_container (&hash_iter, &entry_iter);
+ dbus_message_iter_abandon_container (&iter, &hash_iter);
+ goto oom;
+ }
+
+ if (!bus_match_rule_dump (matchmaker, conn_filter, &arr_iter))
+ {
+ dbus_message_iter_abandon_container (&entry_iter, &arr_iter);
+ dbus_message_iter_abandon_container (&hash_iter, &entry_iter);
+ dbus_message_iter_abandon_container (&iter, &hash_iter);
+ goto oom;
+ }
+
+ if (!dbus_message_iter_close_container (&entry_iter, &arr_iter))
+ {
+ dbus_message_iter_abandon_container (&hash_iter, &entry_iter);
+ dbus_message_iter_abandon_container (&iter, &hash_iter);
+ goto oom;
+ }
+ if (!dbus_message_iter_close_container (&hash_iter, &entry_iter))
+ {
+ dbus_message_iter_abandon_container (&iter, &hash_iter);
+ goto oom;
+ }
+ }
+
+ if (!dbus_message_iter_close_container (&iter, &hash_iter))
+ goto oom;
+
+ if (!bus_transaction_send_from_driver (transaction, caller_connection,
+ reply))
+ goto oom;
+
+ dbus_message_unref (reply);
+ dbus_free_string_array (services);
+ return TRUE;
+
+oom:
+ if (reply != NULL)
+ dbus_message_unref (reply);
+
+ dbus_free_string_array (services);
+
+ BUS_SET_OOM (error);
+ return FALSE;
+}
+
#endif
diff --git a/bus/stats.h b/bus/stats.h
index 0f843db5..dcb022c4 100644
--- a/bus/stats.h
+++ b/bus/stats.h
@@ -35,4 +35,9 @@ dbus_bool_t bus_stats_handle_get_connection_stats (DBusConnection *connection,
DBusMessage *message,
DBusError *error);
+dbus_bool_t bus_stats_handle_get_all_match_rules (DBusConnection *caller_connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error);
+
#endif /* multiple-inclusion guard */
diff --git a/bus/system.conf.in b/bus/system.conf.in
index 851b9e63..3679115e 100644
--- a/bus/system.conf.in
+++ b/bus/system.conf.in
@@ -63,12 +63,17 @@
<allow receive_type="signal"/>
<!-- Allow anyone to talk to the message bus -->
- <allow send_destination="org.freedesktop.DBus"/>
+ <allow send_destination="org.freedesktop.DBus"
+ send_interface="org.freedesktop.DBus" />
+ <allow send_destination="org.freedesktop.DBus"
+ send_interface="org.freedesktop.DBus.Introspectable"/>
<!-- But disallow some specific bus services -->
<deny send_destination="org.freedesktop.DBus"
send_interface="org.freedesktop.DBus"
send_member="UpdateActivationEnvironment"/>
<deny send_destination="org.freedesktop.DBus"
+ send_interface="org.freedesktop.DBus.Debug.Stats"/>
+ <deny send_destination="org.freedesktop.DBus"
send_interface="org.freedesktop.systemd1.Activator"/>
</policy>
@@ -78,13 +83,32 @@
send_interface="org.freedesktop.systemd1.Activator"/>
</policy>
+ <!-- root may monitor the system bus. -->
+ <policy user="root">
+ <allow send_destination="org.freedesktop.DBus"
+ send_interface="org.freedesktop.DBus.Monitoring"/>
+ </policy>
+
+ <!-- If the Stats interface was enabled at compile-time, root may use it.
+ Copy this into system.local.conf or system.d/*.conf if you want to
+ enable other privileged users to view statistics and debug info -->
+ <policy user="root">
+ <allow send_destination="org.freedesktop.DBus"
+ send_interface="org.freedesktop.DBus.Debug.Stats"/>
+ </policy>
+
+ <!-- Include legacy configuration location -->
+ <include ignore_missing="yes">@DBUS_SYSCONFDIR@/dbus-1/system.conf</include>
+
<!-- Config files are placed here that among other things, punch
holes in the above policy for specific services. -->
<includedir>system.d</includedir>
+ <includedir>@DBUS_SYSCONFDIR@/dbus-1/system.d</includedir>
+
<!-- This is included last so local configuration can override what's
in this standard file -->
- <include ignore_missing="yes">system-local.conf</include>
+ <include ignore_missing="yes">@DBUS_SYSCONFDIR@/dbus-1/system-local.conf</include>
<include if_selinux_enabled="yes" selinux_root_relative="yes">contexts/dbus_contexts</include>
diff --git a/bus/systemd-user/dbus.service.in b/bus/systemd-user/dbus.service.in
new file mode 100644
index 00000000..b41f522b
--- /dev/null
+++ b/bus/systemd-user/dbus.service.in
@@ -0,0 +1,11 @@
+[Unit]
+Description=D-Bus User Message Bus
+Documentation=man:dbus-daemon(1)
+Requires=dbus.socket
+
+[Service]
+ExecStart=@EXPANDED_BINDIR@/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation
+ExecReload=@EXPANDED_BINDIR@/dbus-send --print-reply --session --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig
+
+[Install]
+Also=dbus.socket
diff --git a/bus/systemd-user/dbus.socket.in b/bus/systemd-user/dbus.socket.in
new file mode 100644
index 00000000..77958f7c
--- /dev/null
+++ b/bus/systemd-user/dbus.socket.in
@@ -0,0 +1,9 @@
+[Unit]
+Description=D-Bus User Message Bus Socket
+
+[Socket]
+ListenStream=%t/bus
+
+[Install]
+WantedBy=sockets.target
+Also=dbus.service
diff --git a/bus/test-main.c b/bus/test-main.c
index 01d22870..788574fe 100644
--- a/bus/test-main.c
+++ b/bus/test-main.c
@@ -31,6 +31,10 @@
#include <dbus/dbus-message-internal.h>
#include "selinux.h"
+#ifdef DBUS_UNIX
+# include <dbus/dbus-sysdeps-unix.h>
+#endif
+
#ifdef DBUS_ENABLE_EMBEDDED_TESTS
static void
die (const char *failure)
@@ -109,6 +113,11 @@ main (int argc, char **argv)
_dbus_string_init_const (&test_data_dir, dir);
+#ifdef DBUS_UNIX
+ /* close any inherited fds so dbus-spawn's check for close-on-exec works */
+ _dbus_close_all ();
+#endif
+
if (!_dbus_threads_init_debug ())
die ("initializing debug threads");
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
index af6e12ff..e072dfa0 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -12,10 +12,25 @@ if(COMMAND cmake_policy)
cmake_policy(SET CMP0003 NEW)
endif(COMMAND cmake_policy)
+if(CMAKE_MAJOR_VERSION GREATER 2)
+ cmake_policy(SET CMP0026 NEW)
+ if (CMAKE_MAJOR_VERSION GREATER 4 OR CMAKE_MINOR_VERSION GREATER 1)
+ cmake_policy(SET CMP0053 NEW)
+ cmake_policy(SET CMP0054 NEW)
+ endif()
+endif()
# detect version
include(MacrosAutotools)
-autoversion(../configure.ac dbus)
+autoinit(../configure.ac)
+autoversion(dbus)
+
+if(EXISTS ../config.h.in)
+ autoheaderchecks(../config.h.in ConfigureChecks.cmake config.h.cmake)
+else()
+ message(STATUS "Generate config.h.in with autogen.sh to enable cmake header difference check.")
+endif()
+
# used by file version info
set (DBUS_PATCH_VERSION "0")
@@ -63,17 +78,23 @@ if (NOT DBUS_DATADIR)
SET(DBUS_DATADIR ${DATADIR})
endif()
+set(DBUS_PREFIX ${DBUS_INSTALL_DIR})
+
set(prefix ${DBUS_INSTALL_DIR})
set(exec_prefix ${prefix})
set(EXPANDED_LIBDIR ${DBUS_INSTALL_DIR}/lib)
set(EXPANDED_INCLUDEDIR ${DBUS_INSTALL_DIR}/include)
set(EXPANDED_BINDIR ${DBUS_INSTALL_DIR}/bin)
set(EXPANDED_SYSCONFDIR ${DBUS_INSTALL_DIR}/etc)
+set(EXPANDED_LOCALSTATEDIR ${DBUS_INSTALL_DIR}/var)
set(EXPANDED_DATADIR ${DBUS_INSTALL_DIR}/${DBUS_DATADIR})
set(DBUS_MACHINE_UUID_FILE ${DBUS_INSTALL_DIR}/lib/dbus/machine-id)
set(DBUS_BINDIR ${EXPANDED_BINDIR})
set(DBUS_DAEMONDIR ${EXPANDED_BINDIR})
-
+set(DBUS_LOCALSTATEDIR ${EXPANDED_LOCALSTATEDIR})
+set(DBUS_SYSCONFDIR ${EXPANDED_SYSCONFDIR})
+set(DBUS_LIBEXECDIR ${EXPANDED_LIBDIR})
+set(DBUS_DATADIR ${EXPANDED_DATADIR})
#enable building of shared library
SET(BUILD_SHARED_LIBS ON)
@@ -136,7 +157,6 @@ if(VCS)
endif(VCS)
if(WIN32)
- set(CMAKE_DEBUG_POSTFIX "d")
if(MSVC)
# controll folders in msvc projects
include(ProjectSourceGroup)
@@ -182,7 +202,19 @@ if (UNIX AND NOT DBUS_DISABLE_ASSERT)
add_definitions(-DDBUS_BUILT_R_DYNAMIC)
endif (UNIX AND NOT DBUS_DISABLE_ASSERT)
+if(DBUS_WITH_GLIB)
+ autodefine(GLIB_VERSION_MIN_REQUIRED)
+ autodefine(GLIB_VERSION_MAX_ALLOWED)
+endif()
+
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
+if(MSVC)
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /w14018")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /w14018")
+else()
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wsign-compare")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-compare")
+endif()
#########################################################################
# Windows CE (>= 5.0.0)
@@ -289,7 +321,6 @@ endif(NOT MSVC)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
option (DBUS_BUS_ENABLE_INOTIFY "build with inotify support (linux only)" ON)
if(DBUS_BUS_ENABLE_INOTIFY)
- check_include_file(sys/inotify.h HAVE_SYS_INOTIFY_H)
if(NOT HAVE_SYS_INOTIFY_H)
message(FATAL_ERROR "sys/inotify.h not found!")
endif(NOT HAVE_SYS_INOTIFY_H)
@@ -297,10 +328,6 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
elseif("${CMAKE_SYSTEM_NAME}" MATCHES ".*BSD")
option (DBUS_BUS_ENABLE_KQUEUE "build with kqueue support (FreeBSD only)" ON)
if(DBUS_BUS_ENABLE_KQUEUE)
- # cmake check a header by compiling a test program with
- # the header, sys/event.h needs stdint.h and sys/types.h
- # to work.
- check_include_files("stdint.h;sys/types.h;sys/event.h" HAVE_SYS_EVENT_H)
if(NOT HAVE_SYS_EVENT_H)
message(FATAL_ERROR "sys/event.h not found!")
endif(NOT HAVE_SYS_EVENT_H)
@@ -401,13 +428,8 @@ endif (MSVC_IDE)
endif (NOT $ENV{TEMP} STREQUAL "")
endif (NOT $ENV{TMPDIR} STREQUAL "")
-# TODO: fix redhet
-if (WIN32)
- # bus-test expects a non empty string
- set (DBUS_SYSTEM_PID_FILE "/dbus-pid")
-else (WIN32)
- set (DBUS_SYSTEM_PID_FILE ${EXPANDED_LOCALSTATEDIR}/run/dbus/pid)
-endif (WIN32)
+ # Not used on Windows, where there is no system bus
+set (DBUS_SYSTEM_PID_FILE ${DBUS_LOCALSTATEDIR}/run/dbus/pid)
if (WIN32)
set (DBUS_CONSOLE_AUTH_DIR "")
@@ -415,8 +437,6 @@ else (WIN32)
set (DBUS_CONSOLE_AUTH_DIR "/var/run/console/")
endif (WIN32)
-set (DBUS_USER )
-
# This won't work on Windows. It's not meant to - the system bus is
# meaningless on Windows anyway.
#
@@ -425,16 +445,17 @@ set (DBUS_USER )
# and also to connect to. If this ever changes, it'll need to be split into
# two variables, one for the listening address and one for the connecting
# address.
-set (DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "unix:path=${EXPANDED_LOCALSTATEDIR}/run/dbus/system_bus_socket" CACHE STRING "system bus default address")
+set (DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "unix:path=${DBUS_LOCALSTATEDIR}/run/dbus/system_bus_socket" CACHE STRING "system bus default address")
if (WIN32)
set (DBUS_SESSION_BUS_LISTEN_ADDRESS "autolaunch:" CACHE STRING "session bus default listening address")
set (DBUS_SESSION_BUS_CONNECT_ADDRESS "autolaunch:" CACHE STRING "session bus fallback address for clients")
- set (DBUS_SYSTEM_CONFIG_FILE "etc/dbus-1/system.conf")
- set (DBUS_SESSION_CONFIG_FILE "etc/dbus-1/session.conf")
+ set (DBUS_SYSTEM_CONFIG_FILE "share/dbus-1/system.conf")
+ set (DBUS_SESSION_CONFIG_FILE "share/dbus-1/session.conf")
# bus-test expects a non empty string
set (DBUS_USER "Administrator")
+ set (DBUS_TEST_USER "guest")
set (DBUS_SESSION_CONF_MAYBE_AUTH_EXTERNAL "<!--<auth>EXTERNAL</auth>-->")
else (WIN32)
set (DBUS_SESSION_BUS_LISTEN_ADDRESS "unix:tmpdir=${DBUS_SESSION_SOCKET_DIR}" CACHE STRING "session bus default listening address")
@@ -443,7 +464,8 @@ else (WIN32)
set (configdir ${sysconfdir}/dbus-1 )
set (DBUS_SYSTEM_CONFIG_FILE ${configdir}/system.conf)
set (DBUS_SESSION_CONFIG_FILE ${configdir}/session.conf)
- set (DBUS_USER "root")
+ set (DBUS_USER "messagebus")
+ set (DBUS_TEST_USER "nobody")
# For best security, assume that all non-Windows platforms can do
# credentials-passing.
set (DBUS_SESSION_CONF_MAYBE_AUTH_EXTERNAL "<auth>EXTERNAL</auth>")
@@ -483,13 +505,8 @@ endif (DBUS_BUILD_TESTS)
set(DBUS_LIBRARIES dbus-1)
set(DBUS_INTERNAL_LIBRARIES dbus-internal)
-# settings for building and using static internal lib
-# important note: DBUS_INTERNAL_xxxxx_DEFINITIONS must *not* be set when building dbus-1 library
set (DBUS_INTERNAL_ADD_LIBRARY_OPTIONS STATIC)
-set (DBUS_INTERNAL_LIBRARY_DEFINITIONS "-DDBUS_STATIC_BUILD")
-# For now, the CMake build system doesn't support replacing the internal
-# main loop with dbus-glib
-set (DBUS_INTERNAL_CLIENT_DEFINITIONS "-DDBUS_STATIC_BUILD -DDBUS_COMPILATION -DDBUS_TEST_USE_INTERNAL")
+set (DBUS_INTERNAL_CLIENT_DEFINITIONS "-DDBUS_COMPILATION")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h )
@@ -506,6 +523,9 @@ add_subdirectory( dbus )
add_subdirectory( bus )
if (DBUS_BUILD_TESTS)
add_subdirectory( test )
+ add_custom_target(check
+ COMMAND ctest -R ^test-.*
+ )
endif (DBUS_BUILD_TESTS)
add_subdirectory( tools )
add_subdirectory( doc )
@@ -521,7 +541,7 @@ GET_FILENAME_COMPONENT(C_COMPILER ${CMAKE_C_COMPILER} NAME)
GET_FILENAME_COMPONENT(CXX_COMPILER ${CMAKE_CXX_COMPILER} NAME)
message(" D-BUS ${DBUS_VERSION} ")
-message(" =========== ")
+message(" ============ ")
message(" ")
message(" install prefix: ${prefix} ")
message(" install exec_prefix: ${exec_prefix} ")
diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake
index d290b0f2..119b83e6 100644
--- a/cmake/ConfigureChecks.cmake
+++ b/cmake/ConfigureChecks.cmake
@@ -1,24 +1,43 @@
include(CheckIncludeFile)
+include(CheckIncludeFiles)
include(CheckSymbolExists)
include(CheckStructMember)
include(CheckTypeSize)
+check_include_file(alloca.h HAVE_ALLOCA_H)
+check_include_file(byteswap.h HAVE_BYTESWAP_H)
+check_include_file(crt/externs.h HAVE_CRT_EXTERNS_H)
check_include_file(dirent.h HAVE_DIRENT_H) # dbus-sysdeps-util.c
-check_include_file(io.h HAVE_IO_H) # internal
+check_include_file(dlfcn.h HAVE_DLFCN_H)
+check_include_file(execinfo.h HAVE_EXECINFO_H)
+check_include_file(errno.h HAVE_ERRNO_H) # dbus-sysdeps.c
+check_include_file(expat.h HAVE_EXPAT_H)
check_include_file(grp.h HAVE_GRP_H) # dbus-sysdeps-util-win.c
+check_include_file(inttypes.h HAVE_INTTYPES_H) # dbus-pipe.h
+check_include_file(io.h HAVE_IO_H) # internal
+check_include_file(locale.h HAVE_LOCALE_H)
+check_include_file(memory.h HAVE_MEMORY_H)
+check_include_file(signal.h HAVE_SIGNAL_H)
+check_include_file(stdint.h HAVE_STDINT_H) # dbus-pipe.h
+check_include_file(stdlib.h HAVE_STDLIB_H)
+check_include_file(stdio.h HAVE_STDIO_H) # dbus-sysdeps.h
+check_include_file(string.h HAVE_STRING_H)
+check_include_file(strings.h HAVE_STRINGS_H)
+check_include_file(syslog.h HAVE_SYSLOG_H)
+check_include_files("stdint.h;sys/types.h;sys/event.h" HAVE_SYS_EVENT_H)
+check_include_file(sys/inotify.h HAVE_SYS_INOTIFY_H)
+check_include_file(sys/resource.h HAVE_SYS_RESOURCE_H)
+check_include_file(sys/stat.h HAVE_SYS_STAT_H)
+check_include_file(sys/types.h HAVE_SYS_TYPES_H)
+check_include_file(sys/uio.h HAVE_SYS_UIO_H)
check_include_file(sys/poll.h HAVE_POLL) # dbus-sysdeps.c, dbus-sysdeps-win.c
+check_include_file(sys/prctl.h HAVE_SYS_PRCTL_H)
+check_include_file(sys/syslimits.h HAVE_SYS_SYSLIMITS_H) # dbus-sysdeps-unix.c
check_include_file(sys/time.h HAVE_SYS_TIME_H)# dbus-sysdeps-win.c
check_include_file(sys/wait.h HAVE_SYS_WAIT_H)# dbus-sysdeps-win.c
check_include_file(time.h HAVE_TIME_H) # dbus-sysdeps-win.c
check_include_file(ws2tcpip.h HAVE_WS2TCPIP_H)# dbus-sysdeps-win.c
check_include_file(unistd.h HAVE_UNISTD_H) # dbus-sysdeps-util-win.c
-check_include_file(stdio.h HAVE_STDIO_H) # dbus-sysdeps.h
-check_include_file(sys/syslimits.h HAVE_SYS_SYSLIMITS_H) # dbus-sysdeps-unix.c
-check_include_file(errno.h HAVE_ERRNO_H) # dbus-sysdeps.c
-check_include_file(signal.h HAVE_SIGNAL_H)
-check_include_file(locale.h HAVE_LOCALE_H)
-check_include_file(inttypes.h HAVE_INTTYPES_H) # dbus-pipe.h
-check_include_file(stdint.h HAVE_STDINT_H) # dbus-pipe.h
check_symbol_exists(backtrace "execinfo.h" HAVE_BACKTRACE) # dbus-sysdeps.c, dbus-sysdeps-win.c
check_symbol_exists(getgrouplist "grp.h" HAVE_GETGROUPLIST) # dbus-sysdeps.c
@@ -31,11 +50,18 @@ check_symbol_exists(clearenv "stdlib.h" HAVE_CLEARENV) #
check_symbol_exists(writev "sys/uio.h" HAVE_WRITEV) # dbus-sysdeps.c, dbus-sysdeps-win.c
check_symbol_exists(setrlimit "sys/resource.h" HAVE_SETRLIMIT) # dbus-sysdeps.c, dbus-sysdeps-win.c, test/test-segfault.c
check_symbol_exists(socketpair "sys/socket.h" HAVE_SOCKETPAIR) # dbus-sysdeps.c
-check_symbol_exists(socklen_t "sys/socket.h" HAVE_SOCKLEN_T) # dbus-sysdeps-unix.c
check_symbol_exists(setlocale "locale.h" HAVE_SETLOCALE) # dbus-test-main.c
check_symbol_exists(localeconv "locale.h" HAVE_LOCALECONV) # dbus-sysdeps.c
check_symbol_exists(strtoll "stdlib.h" HAVE_STRTOLL) # dbus-send.c
check_symbol_exists(strtoull "stdlib.h" HAVE_STRTOULL) # dbus-send.c
+set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
+check_symbol_exists(pipe2 "fcntl.h;unistd.h" HAVE_PIPE2)
+check_symbol_exists(accept4 "sys/socket.h" HAVE_ACCEPT4)
+check_symbol_exists(dirfd "dirent.h" HAVE_DIRFD)
+check_symbol_exists(inotify_init1 "sys/inotify.h" HAVE_INOTIFY_INIT1)
+check_symbol_exists(SCM_RIGHTS "sys/types.h;sys/socket.h;sys/un.h" HAVE_UNIX_FD_PASSING)
+check_symbol_exists(prctl "sys/prctl.h" HAVE_PRCTL)
+check_symbol_exists(raise "signal.h" HAVE_RAISE)
check_struct_member(cmsgcred cmcred_pid "sys/types.h sys/socket.h" HAVE_CMSGCRED) # dbus-sysdeps.c
@@ -48,6 +74,9 @@ check_type_size("int" SIZEOF_INT)
check_type_size("long" SIZEOF_LONG)
check_type_size("long long" SIZEOF_LONG_LONG)
check_type_size("__int64" SIZEOF___INT64)
+set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h")
+check_type_size("socklen_t" SOCKLEN_T) # dbus-sysdeps-unix.c
+set(CMAKE_EXTRA_INCLUDE_FILES)
# DBUS_INT64_TYPE
if(SIZEOF_INT EQUAL 8)
diff --git a/cmake/bus/CMakeLists.txt b/cmake/bus/CMakeLists.txt
index f5b41cd8..935881ae 100644
--- a/cmake/bus/CMakeLists.txt
+++ b/cmake/bus/CMakeLists.txt
@@ -3,17 +3,16 @@ add_definitions(-DDBUS_COMPILATION)
SET(EFENCE "")
SET(BUS_DIR ${CMAKE_SOURCE_DIR}/../bus)
-set (config_DATA
- session.conf
- system.conf
-)
-
# config files for installation
CONFIGURE_FILE( "${BUS_DIR}/session.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/session.conf" IMMEDIATE @ONLY)
+CONFIGURE_FILE( "${BUS_DIR}/legacy-config/session.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/legacy-config/session.conf" IMMEDIATE @ONLY)
FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/session.d)
-CONFIGURE_FILE( "system.conf.cmake" "${CMAKE_CURRENT_BINARY_DIR}/system.conf" IMMEDIATE @ONLY)
-FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/system.d)
+if(NOT WIN32)
+ CONFIGURE_FILE( "${BUS_DIR}/system.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/system.conf" IMMEDIATE @ONLY)
+ CONFIGURE_FILE( "${BUS_DIR}/legacy-config/system.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/legacy-config/system.conf" IMMEDIATE @ONLY)
+ FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/system.d)
+endif()
# copy services for local daemon start to local service dir data/dbus-1/services
SET (SERVICE_FILES test/data/valid-service-files)
@@ -40,6 +39,8 @@ endif (DBUS_BUS_ENABLE_INOTIFY)
set (BUS_SOURCES
${BUS_DIR}/activation.c
${BUS_DIR}/activation.h
+ ${BUS_DIR}/apparmor.c
+ ${BUS_DIR}/apparmor.h
${BUS_DIR}/bus.c
${BUS_DIR}/bus.h
${BUS_DIR}/config-parser.c
@@ -80,7 +81,11 @@ if(DBUS_ENABLE_STATS)
)
endif(DBUS_ENABLE_STATS)
-include_directories(${XML_INCLUDE_DIR})
+include_directories(
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/..
+ ${XML_INCLUDE_DIR}
+)
add_executable(dbus-daemon ${BUS_SOURCES} ${BUS_DIR}/main.c)
target_link_libraries(dbus-daemon ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY})
@@ -88,8 +93,18 @@ set_target_properties(dbus-daemon PROPERTIES OUTPUT_NAME ${DBUS_DAEMON_NAME})
set_target_properties(dbus-daemon PROPERTIES COMPILE_FLAGS ${DBUS_INTERNAL_CLIENT_DEFINITIONS})
install_targets(/bin dbus-daemon)
-install_files(/etc/dbus-1 FILES ${config_DATA})
-install(DIRECTORY . DESTINATION etc/dbus-1/session.d FILES_MATCHING PATTERN "*.conf")
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/session.conf DESTINATION share/dbus-1)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/legacy-config/session.conf DESTINATION etc/dbus-1)
+install(DIRECTORY DESTINATION share/dbus-1/session.d)
+install(DIRECTORY DESTINATION share/dbus-1/services)
+
+if(NOT WIN32)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/system.conf DESTINATION share/dbus-1)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/legacy-config/system.conf DESTINATION etc/dbus-1)
+ install(DIRECTORY DESTINATION share/dbus-1/system.d)
+ install(DIRECTORY DESTINATION share/dbus-1/system-services)
+ install(DIRECTORY DESTINATION var/run/dbus)
+endif()
if (DBUS_SERVICE)
set (dbus_service_SOURCES
@@ -109,6 +124,16 @@ if (DBUS_ENABLE_EMBEDDED_TESTS)
set(SOURCES ${BUS_SOURCES} ${BUS_DIR}/test-main.c)
add_test_executable(test-bus "${SOURCES}" ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY})
set_target_properties(test-bus PROPERTIES COMPILE_FLAGS ${DBUS_INTERNAL_CLIENT_DEFINITIONS})
+ if (NOT WIN32)
+ set(test_bus_system_SOURCES
+ ${XML_SOURCES}
+ ${BUS_DIR}/config-parser-common.c
+ ${BUS_DIR}/config-parser-trivial.c
+ ${BUS_DIR}/utils.c
+ ${BUS_DIR}/test-system.c
+ )
+ add_test_executable(test-bus-system "${test_bus_system_SOURCES}" ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY} ${DBUS_BUS_LIBS})
+ endif()
endif (DBUS_ENABLE_EMBEDDED_TESTS)
if(MSVC)
@@ -148,6 +173,7 @@ if(NOT WIN32)
set (SOURCES ${LAUNCH_HELPER_SOURCES} ${BUS_DIR}/test-launch-helper.c)
add_test_executable(test-bus-launch-helper "${SOURCES}" ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY})
set_target_properties(test-bus-launch-helper PROPERTIES COMPILE_FLAGS "-DACTIVATION_LAUNCHER_TEST -DACTIVATION_LAUNCHER_DO_OOM")
+ install_targets(/lib dbus-daemon-launch-helper)
endif(NOT WIN32)
#### Init scripts fun
diff --git a/cmake/bus/system.conf.cmake b/cmake/bus/system.conf.cmake
deleted file mode 100644
index ee85ecc4..00000000
--- a/cmake/bus/system.conf.cmake
+++ /dev/null
@@ -1,62 +0,0 @@
-<!-- This configuration file controls the systemwide message bus.
- Add a system-local.conf and edit that rather than changing this
- file directly. -->
-
-<!-- Note that there are any number of ways you can hose yourself
- security-wise by screwing up this file; in particular, you
- probably don't want to listen on any more addresses, add any more
- auth mechanisms, run as a different user, etc. -->
-
-<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
- "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-<busconfig>
-
- <!-- Our well-known bus type, do not change this -->
- <type>system</type>
-
- <!-- Run as special user -->
- <user>@DBUS_USER@</user>
-
- <!-- Fork into daemon mode -->
- <fork/>
-
- <!-- Write a pid file -->
- <pidfile>@DBUS_SYSTEM_PID_FILE@</pidfile>
-
- <!-- Only allow socket-credentials-based authentication -->
- <auth>EXTERNAL</auth>
-
- <!-- Only listen on a local socket. (abstract=/path/to/socket
- means use abstract namespace, don't really create filesystem
- file; only Linux supports this. Use path=/whatever on other
- systems.) -->
- <listen>@DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@</listen>
-
- <policy context="default">
- <!-- Deny everything then punch holes -->
- <deny send_interface="*"/>
- <deny receive_interface="*"/>
- <deny own="*"/>
- <!-- But allow all users to connect -->
- <allow user="*"/>
- <!-- Allow anyone to talk to the message bus -->
- <!-- FIXME I think currently these allow rules are always implicit
- even if they aren't in here -->
- <allow send_destination="org.freedesktop.DBus"/>
- <allow receive_sender="org.freedesktop.DBus"/>
- <!-- valid replies are always allowed -->
- <allow send_requested_reply="true"/>
- <allow receive_requested_reply="true"/>
- </policy>
-
- <!-- Config files are placed here that among other things, punch
- holes in the above policy for specific services. -->
- <includedir>system.d</includedir>
-
- <!-- This is included last so local configuration can override what's
- in this standard file -->
- <include ignore_missing="yes">system-local.conf</include>
-
- <include if_selinux_enabled="yes" selinux_root_relative="yes">contexts/dbus_contexts</include>
-
-</busconfig>
diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake
index 729080f7..d2af3c96 100644
--- a/cmake/config.h.cmake
+++ b/cmake/config.h.cmake
@@ -17,6 +17,7 @@
#cmakedefine DBUS_CONSOLE_AUTH_DIR "@DBUS_CONSOLE_AUTH_DIR@"
#cmakedefine DBUS_DATADIR "@DBUS_DATADIR@"
#cmakedefine DBUS_BINDIR "@DBUS_BINDIR@"
+#cmakedefine DBUS_PREFIX "@DBUS_PREFIX@"
#cmakedefine DBUS_SYSTEM_CONFIG_FILE "@DBUS_SYSTEM_CONFIG_FILE@"
#cmakedefine DBUS_SESSION_CONFIG_FILE "@DBUS_SESSION_CONFIG_FILE@"
#cmakedefine DBUS_DAEMON_NAME "@DBUS_DAEMON_NAME@"
@@ -95,54 +96,84 @@
#cmakedefine DBUS_VA_COPY_AS_ARRAY @DBUS_VA_COPY_AS_ARRAY@
+#cmakedefine DBUS_WITH_GLIB 1
+#cmakedefine GLIB_VERSION_MIN_REQUIRED @GLIB_VERSION_MIN_REQUIRED@
+#cmakedefine GLIB_VERSION_MAX_ALLOWED @GLIB_VERSION_MAX_ALLOWED@
+
// headers
+#cmakedefine HAVE_ALLOCA_H
+#cmakedefine HAVE_BYTESWAP_H
+#cmakedefine HAVE_CRT_EXTERNS_H
+
/* Define to 1 if you have dirent.h */
#cmakedefine HAVE_DIRENT_H 1
-/* Define to 1 if you have io.h */
-#cmakedefine HAVE_IO_H 1
+#cmakedefine HAVE_DLFCN_H
+
+/* Define to 1 if you have errno.h */
+#cmakedefine HAVE_ERRNO_H 1
+
+#cmakedefine HAVE_EXECINFO_H
+#cmakedefine HAVE_EXPAT_H
/* Define to 1 if you have grp.h */
#cmakedefine HAVE_GRP_H 1
-/* Define to 1 if you have sys/poll.h */
-#cmakedefine HAVE_POLL 1
+/* Define to 1 if you have inttypes.h */
+#cmakedefine HAVE_INTTYPES_H 1
-/* Define to 1 if you have sys/time.h */
-#cmakedefine HAVE_SYS_TIME 1
+/* Define to 1 if you have io.h */
+#cmakedefine HAVE_IO_H 1
-/* Define to 1 if you have sys/wait.h */
-#cmakedefine HAVE_SYS_WAIT 1
+/* Define to 1 if you have locale.h */
+#cmakedefine HAVE_LOCALE_H 1
-/* Define to 1 if you have time.h */
-#cmakedefine HAVE_TIME_H 1
+#cmakedefine HAVE_MEMORY_H
-/* Define to 1 if you have ws2tcpip.h */
-#cmakedefine HAVE_WS2TCPIP_H
+/* Define to 1 if you have sys/poll.h */
+#cmakedefine HAVE_POLL 1
-/* Define to 1 if you have unistd.h */
-#cmakedefine HAVE_UNISTD_H 1
+/* Define to 1 if you have signal.h */
+#cmakedefine HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have stdint.h */
+#cmakedefine HAVE_STDINT_H 1
+
+#cmakedefine HAVE_STDLIB_H
/* Define to 1 if you have stdio.h */
#cmakedefine HAVE_STDIO_H 1
+#cmakedefine HAVE_STRINGS_H
+#cmakedefine HAVE_STRING_H
+#cmakedefine HAVE_SYSLOG_H
+#cmakedefine HAVE_SYS_EVENTS_H
+#cmakedefine HAVE_SYS_INOTIFY_H
+#cmakedefine HAVE_SYS_PRCTL_H
+#cmakedefine HAVE_SYS_RESOURCE_H
+#cmakedefine HAVE_SYS_STAT_H
+
/* Define to 1 if you have sys/syslimits.h */
#cmakedefine HAVE_SYS_SYSLIMITS_H 1
-/* Define to 1 if you have errno.h */
-#cmakedefine HAVE_ERRNO_H 1
+/* Define to 1 if you have sys/time.h */
+#cmakedefine HAVE_SYS_TIME_H 1
-/* Define to 1 if you have signal.h */
-#cmakedefine HAVE_SIGNAL_H 1
+#cmakedefine HAVE_SYS_TYPES_H
-/* Define to 1 if you have locale.h */
-#cmakedefine HAVE_LOCALE_H 1
+#cmakedefine HAVE_SYS_UIO_H
-/* Define to 1 if you have inttypes.h */
-#cmakedefine HAVE_INTTYPES_H 1
+/* Define to 1 if you have sys/wait.h */
+#cmakedefine HAVE_SYS_WAIT_H 1
-/* Define to 1 if you have stdint.h */
-#cmakedefine HAVE_STDINT_H 1
+/* Define to 1 if you have time.h */
+#cmakedefine HAVE_TIME_H 1
+
+/* Define to 1 if you have unistd.h */
+#cmakedefine HAVE_UNISTD_H 1
+
+/* Define to 1 if you have ws2tcpip.h */
+#cmakedefine HAVE_WS2TCPIP_H
// symbols
/* Define to 1 if you have backtrace */
@@ -190,12 +221,23 @@
/* Define to 1 if you have strtoull */
#cmakedefine HAVE_STRTOULL 1
+/* Define to 1 if you have pip2 */
+#cmakedefine HAVE_PIPE2
+
+#cmakedefine HAVE_ACCEPT4 1
+#cmakedefine HAVE_DIRFD 1
+#cmakedefine HAVE_INOTIFY_INIT1 1
+#cmakedefine HAVE_UNIX_FD_PASSING 1
+
// structs
/* Define to 1 if you have struct cmsgred */
#cmakedefine HAVE_CMSGCRED 1
#cmakedefine FD_SETSIZE @FD_SETSIZE@
+#cmakedefine DBUS_USER "@DBUS_USER@"
+#cmakedefine DBUS_TEST_USER "@DBUS_TEST_USER@"
+
// system type defines
#if defined(_WIN32) || defined(_WIN64) || defined (_WIN32_WCE)
# define DBUS_WIN
diff --git a/cmake/dbus/CMakeLists.txt b/cmake/dbus/CMakeLists.txt
index a5481b78..17014084 100644
--- a/cmake/dbus/CMakeLists.txt
+++ b/cmake/dbus/CMakeLists.txt
@@ -214,14 +214,12 @@ else (WIN32)
${DBUS_DIR}/dbus-sysdeps-unix.c
${DBUS_DIR}/dbus-sysdeps-pthread.c
${DBUS_DIR}/dbus-userdb.c
- ${DBUS_DIR}/sd-daemon.c
)
set (DBUS_SHARED_HEADERS ${DBUS_SHARED_HEADERS}
${DBUS_DIR}/dbus-server-unix.h
${DBUS_DIR}/dbus-transport-unix.h
${DBUS_DIR}/dbus-sysdeps-unix.h
${DBUS_DIR}/dbus-userdb.h
- ${DBUS_DIR}/sd-daemon.h
)
set (DBUS_UTIL_SOURCES ${DBUS_UTIL_SOURCES}
${DBUS_DIR}/dbus-spawn.c
@@ -261,31 +259,48 @@ add_library(dbus-1 SHARED
${libdbus_SOURCES}
${libdbus_HEADERS}
)
+if(DEFINED DBUS_LIBRARY_REVISION)
+ math(EXPR DBUS_LIBRARY_MAJOR "${DBUS_LIBRARY_CURRENT} - ${DBUS_LIBRARY_AGE}")
+endif()
+
if(WIN32)
+ if(DEFINED DBUS_LIBRARY_REVISION)
+ set_target_properties(dbus-1 PROPERTIES SUFFIX "-${DBUS_LIBRARY_MAJOR}${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ add_custom_command(TARGET dbus-1 POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:dbus-1>" "$<TARGET_FILE_DIR:dbus-1>/${CMAKE_SHARED_LIBRARY_PREFIX}dbus-1${CMAKE_SHARED_LIBRARY_SUFFIX}"
+ COMMENT "Create non versioned dbus-1 library for legacy applications"
+ )
+ install(FILES ${LEGACY_FILE_NAME} DESTINATION bin)
+ endif()
if(WINCE)
target_link_libraries(dbus-1 ws2)
else(WINCE)
target_link_libraries(dbus-1 ws2_32 advapi32 netapi32 iphlpapi)
endif(WINCE)
else(WIN32)
+ if(DEFINED DBUS_LIBRARY_REVISION)
+ set_target_properties(dbus-1 PROPERTIES VERSION ${DBUS_LIBRARY_MAJOR}.${DBUS_LIBRARY_AGE}.${DBUS_LIBRARY_REVISION} SOVERSION ${DBUS_LIBRARY_MAJOR})
+ endif()
target_link_libraries(dbus-1 ${CMAKE_THREAD_LIBS_INIT} rt)
endif(WIN32)
+# Assume that Linux has -Wl,--version-script and other platforms do not
+if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
+ set(SOVERSION ${DBUS_LIBRARY_MAJOR})
+ configure_file(${DBUS_DIR}/Version.in ${CMAKE_CURRENT_BINARY_DIR}/Version)
+ set_target_properties(dbus-1 PROPERTIES LINK_FLAGS -Wl,--version-script=${CMAKE_CURRENT_BINARY_DIR}/Version)
+endif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
+
install(TARGETS dbus-1 ${INSTALL_TARGETS_DEFAULT_ARGS})
install_files(/include/dbus FILES ${dbusinclude_HEADERS})
### Internal library, used for the daemon, tools and tests, compiled statically.
add_library(dbus-internal ${DBUS_INTERNAL_ADD_LIBRARY_OPTIONS}
- ${DBUS_LIB_SOURCES}
- ${DBUS_LIB_HEADERS}
- ${DBUS_SHARED_SOURCES}
- ${DBUS_SHARED_HEADERS}
${DBUS_UTIL_SOURCES}
${DBUS_UTIL_HEADERS}
)
-target_link_libraries(dbus-internal)
-set_target_properties(dbus-internal PROPERTIES COMPILE_FLAGS ${DBUS_INTERNAL_LIBRARY_DEFINITIONS})
+target_link_libraries(dbus-internal dbus-1)
if(WIN32)
if(WINCE)
target_link_libraries(dbus-internal ws2)
diff --git a/cmake/doc/CMakeLists.txt b/cmake/doc/CMakeLists.txt
index 7fdfc219..f21e84e7 100644
--- a/cmake/doc/CMakeLists.txt
+++ b/cmake/doc/CMakeLists.txt
@@ -20,6 +20,8 @@ find_program(MEINPROC4_EXECUTABLE meinproc4)
find_program(XMLTO_EXECUTABLE xmlto)
+find_program(CYGPATH_EXECUTABLE cygpath)
+
if (MEINPROC4_EXECUTABLE OR XMLTO_EXECUTABLE)
OPTION(DBUS_ENABLE_XML_DOCS "build XML documentation (requires xmlto or meinproc4)" ON)
ADD_CUSTOM_TARGET(xmldoc ALL)
@@ -71,6 +73,19 @@ macro (DOCBOOK _sources _format)
)
endif ()
if (XMLTO_EXECUTABLE)
+ if (MSYS)
+ if (CYGPATH_EXECUTABLE)
+ execute_process(
+ COMMAND cygpath ${_infile}
+ OUTPUT_VARIABLE _infile)
+ else ()
+ execute_process(COMMAND dirname ${_infile} OUTPUT_VARIABLE _path)
+ string(STRIP ${_path} _path)
+ execute_process(COMMAND sh -c "cd ${_path}; pwd -W" OUTPUT_VARIABLE _path)
+ string(STRIP ${_path} _path)
+ set(_infile "${_path}/${_name}")
+ endif(CYGPATH_EXECUTABLE)
+ endif (MSYS)
ADD_CUSTOM_COMMAND(
OUTPUT ${_outfile}
COMMAND ${XMLTO_EXECUTABLE} -vv ${_format} ${_infile}
@@ -122,20 +137,26 @@ configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-daemon.1.xml.in ${CMAKE_BINARY_DI
configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-launch.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-launch.1.xml)
configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-monitor.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-monitor.1.xml)
configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-send.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-send.1.xml)
+configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-test-tool.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-test-tool.1.xml)
+configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-update-activation-environment.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-update-activation-environment.1.xml)
configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-uuidgen.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-uuidgen.1.xml)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-cleanup-sockets.1.xml html-nochunks)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-daemon.1.xml html-nochunks)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-launch.1.xml html-nochunks)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-monitor.1.xml html-nochunks)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-send.1.xml html-nochunks)
+DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-test-tool.1.xml html-nochunks)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-uuidgen.1.xml html-nochunks)
+DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-update-activation-environment.1.xml html-nochunks)
if (UNIX)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-daemon.1.xml man)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-monitor.1.xml man)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-send.1.xml man)
+ DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-test-tool.1.xml man)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-launch.1.xml man)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-uuidgen.1.xml man)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-cleanup-sockets.1.xml man)
+ DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-update-activation-environment.1.xml man)
endif()
#
# handle html index file
diff --git a/cmake/modules/MacrosAutotools.cmake b/cmake/modules/MacrosAutotools.cmake
index 68e8ae51..8bb83cdf 100644
--- a/cmake/modules/MacrosAutotools.cmake
+++ b/cmake/modules/MacrosAutotools.cmake
@@ -1,6 +1,21 @@
#
+# cmake package for autotools support
+#
# @Author Ralf Habacker
#
+
+#
+# load autotools configure file into an internal list named _configure_ac
+#
+macro(autoinit config)
+ set(_configure_ac_name ${config})
+ file(READ ${config} _configure_ac_raw)
+ # Convert file contents into a CMake list (where each element in the list
+ # is one line of the file)
+ STRING(REGEX REPLACE ";" "\\\\;" _configure_ac "${_configure_ac_raw}")
+ STRING(REGEX REPLACE "\n" ";" _configure_ac "${_configure_ac}")
+endmacro()
+
# extracts version information from autoconf config file
# and set related cmake variables
#
@@ -10,16 +25,20 @@
# ${prefix}_MAJOR_VERSION
# ${prefix}_MINOR_VERSION
# ${prefix}_MICRO_VERSION
+# ${prefix}_LIBRARY_AGE
+# ${prefix}_LIBRARY_REVISION
+# ${prefix}_LIBRARY_CURRENT
#
-macro(autoversion config prefix)
- file (READ ${config} _configure_ac)
- string(TOUPPER ${prefix} prefix_upper)
- string (REGEX REPLACE ".*${prefix}_major_version], .([0-9]+).*" "\\1" ${prefix_upper}_MAJOR_VERSION ${_configure_ac})
- string (REGEX REPLACE ".*${prefix}_minor_version], .([0-9]+).*" "\\1" ${prefix_upper}_MINOR_VERSION ${_configure_ac})
- string (REGEX REPLACE ".*${prefix}_micro_version], .([0-9]+).*" "\\1" ${prefix_upper}_MICRO_VERSION ${_configure_ac})
- set (${prefix_upper}_VERSION ${${prefix_upper}_MAJOR_VERSION}.${${prefix_upper}_MINOR_VERSION}.${${prefix_upper}_MICRO_VERSION})
- set (${prefix_upper}_VERSION_STRING "${${prefix_upper}_VERSION}")
-
+macro(autoversion prefix)
+ string(TOUPPER ${prefix} prefix_upper)
+ string (REGEX REPLACE ".*${prefix}_major_version], .([0-9]+).*" "\\1" ${prefix_upper}_MAJOR_VERSION ${_configure_ac_raw})
+ string (REGEX REPLACE ".*${prefix}_minor_version], .([0-9]+).*" "\\1" ${prefix_upper}_MINOR_VERSION ${_configure_ac_raw})
+ string (REGEX REPLACE ".*${prefix}_micro_version], .([0-9]+).*" "\\1" ${prefix_upper}_MICRO_VERSION ${_configure_ac_raw})
+ set (${prefix_upper}_VERSION ${${prefix_upper}_MAJOR_VERSION}.${${prefix_upper}_MINOR_VERSION}.${${prefix_upper}_MICRO_VERSION})
+ set (${prefix_upper}_VERSION_STRING "${${prefix_upper}_VERSION}")
+ string (REGEX REPLACE ".*LT_AGE=([0-9]+).*" "\\1" ${prefix_upper}_LIBRARY_AGE ${_configure_ac_raw})
+ string (REGEX REPLACE ".*LT_CURRENT=([0-9]+).*" "\\1" ${prefix_upper}_LIBRARY_CURRENT ${_configure_ac_raw})
+ string (REGEX REPLACE ".*LT_REVISION=([0-9]+).*" "\\1" ${prefix_upper}_LIBRARY_REVISION ${_configure_ac_raw})
endmacro()
#
@@ -57,7 +76,7 @@ macro(autopackage name version url support_url)
set(PACKAGE ${name})
set(VERSION ${DBUS_VERSION_STRING})
- set(AUTOPACKAGE_CONFIG_H_TEMPLATE "/* generated by cmake macro autopackage */\n
+ string(CONFIGURE "/* generated by cmake macro autopackage */\n
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT \"@PACKAGE_BUGREPORT@\"
@@ -79,10 +98,59 @@ macro(autopackage name version url support_url)
/* defined by autotools package */
#define PACKAGE \"@PACKAGE@\"
#define VERSION \"@VERSION@\"
-")
+" AUTOPACKAGE_CONFIG_H_TEMPLATE)
endmacro(autopackage)
#
+# define a cmake variable from autotools AC_DEFINE statement
+#
+macro(autodefine name)
+ foreach(line ${_configure_ac})
+ if(line MATCHES ".*AC_DEFINE(.*${name}.*).*")
+ string (REGEX REPLACE ".*AC_DEFINE(.*).*" "\\1" value ${line})
+ string (REGEX REPLACE ".*,(.*),.*" "\\1" value2 ${value})
+ string (REPLACE "[" "" value3 ${value2})
+ string (REPLACE "]" "" value4 ${value3})
+ set(${name} ${value4})
+ endif()
+ endforeach()
+endmacro()
+
+macro(autoheaderchecks config_h_in configure_checks_file config_h_cmake)
+ file(READ ${configure_checks_file} configure_checks_file_raw)
+ file(READ ${config_h_in} _config_h_in_raw)
+ file(READ ${config_h_cmake} _config_h_cmake_raw)
+ STRING(REGEX REPLACE ";" "\\\\;" _config_h_in "${_config_h_in_raw}")
+ STRING(REGEX REPLACE "\n" ";" _config_h_in "${_config_h_in}")
+ foreach(line ${_config_h_in})
+ #message(STATUS ${line})
+ if(line MATCHES ".*HAVE_.*_H.*")
+ string (REGEX REPLACE ".*HAVE_(.*)_H.*" "\\1" key ${line})
+ set(full_key "HAVE_${key}_H")
+ if(key MATCHES ".*_.*")
+ string(REGEX MATCH "^[A-Z0-9]+" dir ${key})
+ string(REGEX MATCH "[A-Z0-9]+$" file ${key})
+ string(TOLOWER ${dir} dirname)
+ string(TOLOWER ${file} filename)
+ set(check "check_include_file(${dirname}/${filename}.h ${full_key})")
+ set(config_define "#cmakedefine ${full_key}")
+ else()
+ set(file ${key})
+ string(TOLOWER ${file} filename)
+ set(check "check_include_file(${filename}.h ${full_key})")
+ set(config_define "#cmakedefine ${full_key}")
+ endif()
+ if(NOT configure_checks_file_raw MATCHES ".*${full_key}.*")
+ message("${check}")
+ endif()
+ if(NOT _config_h_cmake_raw MATCHES "${full_key}")
+ message("${config_define}")
+ endif()
+ endif()
+ endforeach()
+endmacro(autoheaderchecks)
+
+#
# parses config.h template and create cmake equivalent
# not implemented yet
#
diff --git a/cmake/test/CMakeLists.txt b/cmake/test/CMakeLists.txt
index 7c91a952..b961ad06 100644
--- a/cmake/test/CMakeLists.txt
+++ b/cmake/test/CMakeLists.txt
@@ -2,6 +2,8 @@ include_directories(${CMAKE_SOURCE_DIR}/../test)
add_definitions(${DBUS_INTERNAL_CLIENT_DEFINITIONS})
+include_directories(${CMAKE_SOURCE_DIR}/../test)
+
set(DBUS_SESSION_BUS_LISTEN_ADDRESS ${TEST_LISTEN})
add_library(dbus-testutils STATIC
@@ -12,6 +14,10 @@ target_link_libraries(dbus-testutils ${DBUS_INTERNAL_LIBRARIES})
add_subdirectory( name-test )
+set (manual-dir-iter_SOURCES
+ ${CMAKE_SOURCE_DIR}/../test/manual-dir-iter.c
+)
+
set (test-service_SOURCES
${CMAKE_SOURCE_DIR}/../test/test-service.c
)
@@ -52,6 +58,11 @@ set (manual-tcp_SOURCES
${CMAKE_SOURCE_DIR}/../test/manual-tcp.c
)
+set (manual-paths_SOURCES
+ ${CMAKE_SOURCE_DIR}/../test/manual-paths.c
+)
+
+add_helper_executable(manual-dir-iter ${manual-dir-iter_SOURCES} ${DBUS_INTERNAL_LIBRARIES})
add_helper_executable(test-service ${test-service_SOURCES} dbus-testutils)
add_helper_executable(test-names ${test-names_SOURCES} dbus-testutils)
add_test_executable(test-shell ${test-shell_SOURCES} ${DBUS_INTERNAL_LIBRARIES})
@@ -62,9 +73,19 @@ add_helper_executable(test-exit ${test-exit_SOURCES} ${DBUS_INTERNAL_LIBRARIES})
add_helper_executable(test-segfault ${test-segfault_SOURCES} ${DBUS_INTERNAL_LIBRARIES})
add_helper_executable(test-sleep-forever ${test-sleep-forever_SOURCES} ${DBUS_INTERNAL_LIBRARIES})
add_test_executable(manual-tcp ${manual-tcp_SOURCES} ${DBUS_INTERNAL_LIBRARIES})
+if(WIN32)
+ add_helper_executable(manual-paths ${manual-paths_SOURCES} ${DBUS_INTERNAL_LIBRARIES})
+endif()
if(DBUS_WITH_GLIB)
message(STATUS "with glib test apps")
+
+ add_library(dbus-testutils-glib STATIC
+ ${CMAKE_SOURCE_DIR}/../test/test-utils-glib.h
+ ${CMAKE_SOURCE_DIR}/../test/test-utils-glib.c
+ )
+ target_link_libraries(dbus-testutils-glib dbus-testutils ${DBUS_INTERNAL_LIBRARIES})
+
add_definitions(
${GLIB2_DEFINITIONS}
${GOBJECT_DEFINITIONS}
@@ -73,11 +94,13 @@ if(DBUS_WITH_GLIB)
${GLIB2_INCLUDE_DIR}
${GOBJECT_INCLUDE_DIR}
)
- set(TEST_LIBRARIES ${DBUS_INTERNAL_LIBRARIES} dbus-testutils ${GLIB2_LIBRARIES} ${GOBJECT_LIBRARIES})
+
+ set(TEST_LIBRARIES ${DBUS_INTERNAL_LIBRARIES} dbus-testutils dbus-testutils-glib ${GLIB2_LIBRARIES} ${GOBJECT_LIBRARIES})
add_test_executable(test-corrupt ${CMAKE_SOURCE_DIR}/../test/corrupt.c ${TEST_LIBRARIES})
add_test_executable(test-dbus-daemon ${CMAKE_SOURCE_DIR}/../test/dbus-daemon.c ${TEST_LIBRARIES})
add_test_executable(test-dbus-daemon-eavesdrop ${CMAKE_SOURCE_DIR}/../test/dbus-daemon-eavesdrop.c ${TEST_LIBRARIES})
+ add_test_executable(test-fdpass ${CMAKE_SOURCE_DIR}/../test/fdpass.c ${TEST_LIBRARIES})
add_test_executable(test-loopback ${CMAKE_SOURCE_DIR}/../test/loopback.c ${TEST_LIBRARIES})
add_test_executable(test-marshal ${CMAKE_SOURCE_DIR}/../test/marshal.c ${TEST_LIBRARIES})
add_test_executable(test-refs ${CMAKE_SOURCE_DIR}/../test/internals/refs.c ${TEST_LIBRARIES})
@@ -156,7 +179,10 @@ ENDFOREACH(FILE_TYPE)
MESSAGE(STATUS "Copying generated bus config files to test directory")
set (OUTDIR ${CMAKE_BINARY_DIR}/test/data/valid-config-files)
-FILE(GLOB FILES "${CMAKE_SOURCE_DIR}/../bus/*.conf.in" )
+SET(FILES
+ "${CMAKE_SOURCE_DIR}/../bus/session.conf.in"
+ "${CMAKE_SOURCE_DIR}/../bus/system.conf.in"
+)
FILE(MAKE_DIRECTORY ${OUTDIR})
FOREACH(FILE ${FILES})
GET_FILENAME_COMPONENT(FILENAME ${FILE} NAME)
@@ -167,7 +193,3 @@ FOREACH(FILE ${FILES})
MESSAGE("FROM: ${FILE}\nTO: ${TARGET}\n")
ENDIF (CONFIG_VERBOSE)
ENDFOREACH(FILE)
-
-add_custom_target(check
- COMMAND ctest -R ^test-.*
-)
diff --git a/cmake/tools/CMakeLists.txt b/cmake/tools/CMakeLists.txt
index ddbd5bcf..6a2e999d 100644
--- a/cmake/tools/CMakeLists.txt
+++ b/cmake/tools/CMakeLists.txt
@@ -1,13 +1,34 @@
+add_definitions("-DDBUS_COMPILATION")
+
set (dbus_send_SOURCES
../../tools/dbus-print-message.c
../../tools/dbus-print-message.h
../../tools/dbus-send.c
+ ../../tools/tool-common.c
+ ../../tools/tool-common.h
)
set (dbus_monitor_SOURCES
../../tools/dbus-monitor.c
../../tools/dbus-print-message.c
../../tools/dbus-print-message.h
+ ../../tools/tool-common.c
+ ../../tools/tool-common.h
+)
+
+set (dbus_test_tool_SOURCES
+ ../../tools/dbus-echo.c
+ ../../tools/dbus-spam.c
+ ../../tools/tool-common.c
+ ../../tools/tool-common.h
+ ../../tools/test-tool.c
+ ../../tools/test-tool.h
+)
+
+set (dbus_update_activation_environment_SOURCES
+ ../../tools/dbus-update-activation-environment.c
+ ../../tools/tool-common.c
+ ../../tools/tool-common.h
)
if (WIN32)
@@ -17,6 +38,8 @@ set (dbus_launch_SOURCES
else (WIN32)
set (dbus_launch_SOURCES
../../tools/dbus-launch.c
+ ../../tools/tool-common.c
+ ../../tools/tool-common.h
)
endif (WIN32)
@@ -35,8 +58,16 @@ add_executable(dbus-send ${dbus_send_SOURCES})
target_link_libraries(dbus-send ${DBUS_LIBRARIES})
install_targets(/bin dbus-send )
+add_executable(dbus-test-tool ${dbus_test_tool_SOURCES})
+target_link_libraries(dbus-test-tool ${DBUS_LIBRARIES})
+install_targets(/bin dbus-test-tool )
+
+add_executable(dbus-update-activation-environment ${dbus_update_activation_environment_SOURCES})
+target_link_libraries(dbus-update-activation-environment ${DBUS_LIBRARIES})
+install_targets(/bin dbus-update-activation-environment )
+
add_executable(dbus-launch ${dbus_launch_SOURCES})
-target_link_libraries(dbus-launch )
+target_link_libraries(dbus-launch ${DBUS_LIBRARIES})
if (DBUS_BUILD_X11)
target_link_libraries(dbus-launch ${X11_LIBRARIES} )
endif (DBUS_BUILD_X11)
@@ -45,3 +76,6 @@ install_targets(/bin dbus-launch )
add_executable(dbus-monitor ${dbus_monitor_SOURCES})
target_link_libraries(dbus-monitor ${DBUS_LIBRARIES})
install_targets(/bin dbus-monitor )
+
+# create the /var/lib/dbus directory for dbus-uuidgen
+install(DIRECTORY DESTINATION var/lib/dbus)
diff --git a/configure.ac b/configure.ac
index f8f2e182..2f47f6b8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,18 +2,19 @@ dnl -*- mode: m4 -*-
AC_PREREQ([2.63])
m4_define([dbus_major_version], [1])
-m4_define([dbus_minor_version], [8])
-m4_define([dbus_micro_version], [19])
+m4_define([dbus_minor_version], [9])
+m4_define([dbus_micro_version], [17])
m4_define([dbus_version],
[dbus_major_version.dbus_minor_version.dbus_micro_version])
AC_INIT([dbus],[dbus_version],[https://bugs.freedesktop.org/enter_bug.cgi?product=dbus],[dbus])
+AC_CONFIG_AUX_DIR([build-aux])
AC_CANONICAL_HOST
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
-AM_INIT_AUTOMAKE([1.10 tar-ustar -Wno-portability])
+AM_INIT_AUTOMAKE([1.13 tar-ustar -Wno-portability subdir-objects])
GETTEXT_PACKAGE=dbus-1
AC_SUBST(GETTEXT_PACKAGE)
@@ -33,20 +34,22 @@ AC_DEFINE_UNQUOTED(DBUS_DAEMON_NAME,"dbus-daemon",[Name of executable])
#
## increment if the interface has additions, changes, removals.
-LT_CURRENT=11
+LT_CURRENT=17
## increment any time the source changes; set to
## 0 if you increment CURRENT
-LT_REVISION=12
+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=8
+LT_AGE=14
AC_SUBST(LT_CURRENT)
AC_SUBST(LT_REVISION)
AC_SUBST(LT_AGE)
+SOVERSION=`expr ${LT_CURRENT} - ${LT_AGE}`
+AC_SUBST([SOVERSION])
DBUS_MAJOR_VERSION=dbus_major_version
DBUS_MINOR_VERSION=dbus_minor_version
@@ -71,6 +74,15 @@ COMPILER_COVERAGE
COMPILER_OPTIMISATIONS
PKG_PROG_PKG_CONFIG
+# TAP test driver support
+AC_PROG_AWK
+AC_REQUIRE_AUX_FILE([tap-driver.sh])
+
+# This must come before we set up compiler warnings because it assumes
+# non-use of -Werror=missing-prototypes
+gl_VISIBILITY
+AM_CONDITIONAL([HAVE_VISIBILITY], [test "x$HAVE_VISIBILITY" = x1])
+
# Initialize libtool
LT_INIT([win32-dll])
LT_LANG([Windows Resource])
@@ -157,8 +169,16 @@ AC_ARG_ENABLE(asserts, AS_HELP_STRING([--enable-asserts],[include assertion chec
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([ducktype-docs],
+ AS_HELP_STRING([--enable-ducktype-docs],
+ [build Ducktype documentation (requires Ducktype)]),
+ [enable_ducktype_docs=$enableval], [enable_ducktype_docs=auto])
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([apparmor],
+ [AS_HELP_STRING([--enable-apparmor], [build with AppArmor support])],
+ [enable_apparmor=$enableval],
+ [enable_apparmor=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(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)
@@ -175,6 +195,9 @@ AC_ARG_WITH(console-auth-dir, AS_HELP_STRING([--with-console-auth-dir=[dirname]]
AC_ARG_WITH(console-owner-file, AS_HELP_STRING([--with-console-owner-file=[filename]],[file whose owner determines current console owner]))
AC_ARG_WITH(launchd-agent-dir, AS_HELP_STRING([--with-launchd-agent-dir=[dirname]],[directory to put the launchd agent (default: /Library/LaunchAgents)]))
AC_ARG_WITH(dbus_user, AS_HELP_STRING([--with-dbus-user=<user>],[User for running the DBUS daemon (messagebus)]))
+AC_ARG_WITH([test_user],
+ [AS_HELP_STRING([--with-test-user=<user>],
+ [Unprivileged user for regression tests, other than root and the dbus_user (default: nobody)])])
AC_ARG_WITH(dbus_daemondir, AS_HELP_STRING([--with-dbus-daemondir=[dirname]],[Directory for installing the DBUS daemon]))
AC_ARG_ENABLE([embedded-tests],
@@ -193,7 +216,7 @@ AC_ARG_ENABLE([tests],
[
if test "x$enableval" = xyes; then
AC_MSG_NOTICE([Full test coverage was requested with --enable-tests=yes])
- AC_MSG_NOTICE([This has many dependencies (GLib, dbus-glib, Python)])
+ AC_MSG_NOTICE([This has many dependencies (GLib, Python etc.)])
fi
enable_embedded_tests=$enableval
enable_modular_tests=$enableval
@@ -214,14 +237,14 @@ fi
# default (unless you don't have GLib), because they don't bloat the library
# or binaries.
-AC_DEFINE([GLIB_VERSION_MIN_REQUIRED], [GLIB_VERSION_2_26], [Ignore post-2.26 deprecations])
-AC_DEFINE([GLIB_VERSION_MAX_ALLOWED], [GLIB_VERSION_2_32], [Prevent post-2.32 APIs])
+AC_DEFINE([GLIB_VERSION_MIN_REQUIRED], [GLIB_VERSION_2_36], [Ignore post-2.36 deprecations])
+AC_DEFINE([GLIB_VERSION_MAX_ALLOWED], [GLIB_VERSION_2_38], [Prevent post-2.38 APIs])
with_glib=yes
AS_IF([test "x$enable_modular_tests" != xno],
[
- PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.24, gio-2.0 >= 2.24],
+ PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.36, gio-2.0 >= 2.36],
[],
[if test "x$enable_modular_tests" = xyes; then
AC_MSG_NOTICE([Full test coverage (--enable-modular-tests=yes or --enable-tests=yes) requires GLib])
@@ -232,22 +255,6 @@ AS_IF([test "x$enable_modular_tests" != xno],
],
[with_glib=no])
-# Not required, because we can use internal APIs (but that makes the
-# "installable tests" less useful as integration tests)
-AC_ARG_WITH([dbus_glib],
- [AS_HELP_STRING([--with-dbus-glib], [Use dbus-glib for regression tests])],
- [],
- [with_dbus_glib=auto])
-AS_IF([test "x$with_dbus_glib" != xno],
- [PKG_CHECK_MODULES([DBUS_GLIB], [dbus-glib-1],
- [],
- [AS_IF([test "x$with_dbus_glib" = xyes],
- dnl specifically requested, but not found
- [AC_MSG_ERROR([$DBUS_GLIB_ERRORS])],
- dnl else: assumed to be "auto"
- [with_dbus_glib=no])])])
-AM_CONDITIONAL([DBUS_WITH_DBUS_GLIB], [test "x$with_dbus_glib" != xno])
-
if test "x$enable_modular_tests" != xno; then
AC_DEFINE([DBUS_ENABLE_MODULAR_TESTS], [1],
[Define to build independent test binaries])
@@ -270,14 +277,14 @@ AM_CONDITIONAL([DBUS_ENABLE_INSTALLED_TESTS],
if test "x$enable_tests" = xyes; then
# full test coverage is required, Python is a hard dependency
- AC_MSG_NOTICE([Full test coverage (--enable-tests=yes) requires Python, dbus-python, pygobject])
+ AC_MSG_NOTICE([Full test coverage (--enable-tests=yes) requires Python, dbus-python, pygi])
AM_PATH_PYTHON([2.6])
AC_MSG_CHECKING([for Python modules for full test coverage])
- if "$PYTHON" -c "import dbus, gobject, dbus.mainloop.glib"; then
+ if "$PYTHON" -c "import dbus, gi.repository.GObject, dbus.mainloop.glib"; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
- AC_MSG_ERROR([cannot import dbus, gobject, dbus.mainloop.glib Python modules])
+ AC_MSG_ERROR([cannot import dbus, gi.repository.GObject, dbus.mainloop.glib Python modules])
fi
else
# --enable-tests not given: do not abort if Python is missing
@@ -598,7 +605,7 @@ AC_DEFINE_UNQUOTED([DBUS_USE_SYNC], [$have_sync], [Use the gcc __sync extension]
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 setlocale localeconv strtoll strtoull issetugid getresuid)
+AC_CHECK_FUNCS([vsnprintf vasprintf nanosleep usleep setenv clearenv unsetenv socketpair getgrouplist fpathconf setrlimit poll setlocale localeconv strtoll strtoull issetugid getresuid setresuid getrlimit])
AC_CHECK_HEADERS([syslog.h])
if test "x$ac_cv_header_syslog_h" = "xyes"; then
@@ -676,7 +683,10 @@ AC_CHECK_HEADERS(sys/resource.h)
AC_CHECK_HEADERS(dirent.h)
-AC_CHECK_HEADERS(execinfo.h, [AC_CHECK_FUNCS(backtrace)])
+AC_CHECK_HEADERS([execinfo.h],
+ [AC_SEARCH_LIBS([backtrace], [execinfo],
+ [AC_DEFINE([HAVE_BACKTRACE], [1],
+ [Define to 1 if you have backtrace().])])])
AC_CHECK_HEADERS(errno.h)
@@ -822,6 +832,11 @@ if test x$dbus_have_struct_cmsgcred = xyes; then
AC_DEFINE(HAVE_CMSGCRED,1,[Have cmsgcred structure])
fi
+AC_CHECK_MEMBER([struct unpcbid.unp_pid],
+ [AC_DEFINE([HAVE_UNPCBID], 1, [Have unpcbid structure])],
+ [],
+ [[#include <sys/un.h>]])
+
AC_CHECK_FUNCS(getpeerucred getpeereid)
AC_CHECK_FUNCS(pipe2 accept4)
@@ -1037,6 +1052,22 @@ else
SELINUX_LIBS=
fi
+# AppArmor detection
+AS_IF([test x$enable_apparmor = xno],
+ [have_apparmor=no],
+ [
+ PKG_CHECK_MODULES([APPARMOR], [libapparmor >= 2.8.95],
+ [have_apparmor=yes], [have_apparmor=no])
+
+ AS_IF([test x$enable_apparmor = xauto && test x$have_apparmor = xno],
+ [AC_MSG_WARN([Sufficiently new AppArmor library not found])])
+ AS_IF([test x$enable_apparmor != xauto && test x$have_apparmor = xno],
+ [AC_MSG_ERROR([AppArmor explicitly required, and AppArmor library not found])])
+ ])
+
+AS_IF([test x$have_apparmor = xyes],
+ [AC_DEFINE([HAVE_APPARMOR], [1], [AppArmor Support])])
+
# inotify checks
if test x$enable_inotify = xno ; then
have_inotify=no;
@@ -1250,7 +1281,7 @@ if test x$with_valgrind != xno; then
fi
#### Set up final flags
-LIBDBUS_LIBS="$THREAD_LIBS $NETWORK_libs"
+LIBDBUS_LIBS="$THREAD_LIBS $NETWORK_libs $SYSTEMD_LIBS"
AC_SUBST([LIBDBUS_LIBS])
### X11 detection
@@ -1343,13 +1374,12 @@ TP_COMPILER_WARNINGS([WARNING_CFLAGS],
dnl - unused-parameter is to make writing callbacks less annoying
dnl
dnl To be fixed one day:
- dnl - sign-compare and pointer-sign are workarounds for fd.o #17433
+ dnl - pointer-sign is a workaround for fd.o #15522
dnl - type-limits is probably a bug too, but having the rest of -Wextra
dnl is better than nothing
[$DISABLE_UNUSED_WARNINGS \
missing-field-initializers \
unused-parameter \
- sign-compare \
pointer-sign \
type-limits \
])
@@ -1385,6 +1415,11 @@ case $host_os in
;;
esac
+### Detect if ld supports --version-script
+
+gl_LD_VERSION_SCRIPT
+AM_CONDITIONAL([HAVE_LD_VERSION_SCRIPT],
+ [test "x$have_ld_version_script" = xyes])
### Doxygen Documentation
AC_PATH_PROG(DOXYGEN, doxygen, no)
@@ -1417,6 +1452,36 @@ AC_MSG_RESULT($enable_doxygen_docs)
AC_CHECK_PROGS([XSLTPROC], [xsltproc])
AM_CONDITIONAL([DBUS_HAVE_XSLTPROC], [test "x$XSLTPROC" != "x"])
+### Ducktype/Yelp documentation
+
+AC_PATH_PROG([DUCKTYPE],[ducktype],[no])
+AC_PATH_PROG([YELP_BUILD],[yelp-build],[no])
+
+AC_MSG_CHECKING([whether to build Ducktype documentation])
+
+AS_IF([test "$DUCKTYPE" = "no"],[have_ducktype=no],[have_ducktype=yes])
+AS_IF([test "$YELP_BUILD" = "no"],[have_yelp_build=no],[have_yelp_build=yes])
+
+AS_IF([test "$enable_ducktype_docs" = "auto"],[
+ AS_IF([test "$have_ducktype" = "no" || test "$have_yelp_build" = "no"],[
+ enable_ducktype_docs=no
+ ],[
+ enable_ducktype_docs=yes
+ ])
+])
+
+AS_IF([test "$enable_ducktype_docs" = "yes"],[
+ AS_IF([test "$have_ducktype" = "no"],[
+ AC_MSG_ERROR([Building Ducktype docs explicitly required, but ducktype not found])
+ ])
+ AS_IF([test "$have_yelp_build" = "no"],[
+ AC_MSG_ERROR([Building Ducktype docs explicitly required, but yelp-build not found])
+ ])
+])
+
+AM_CONDITIONAL([DBUS_DUCKTYPE_DOCS_ENABLED],[test "$enable_ducktype_docs" = "yes"])
+AC_MSG_RESULT([$enable_ducktype_docs])
+
### XML Documentation
AC_PATH_PROG(XMLTO, xmlto, no)
@@ -1447,7 +1512,8 @@ AM_CONDITIONAL(DBUS_XML_DOCS_ENABLED, test x$enable_xml_docs = xyes)
AC_MSG_RESULT($enable_xml_docs)
AM_CONDITIONAL(DBUS_CAN_UPLOAD_DOCS,
- [test x$enable_doxygen_docs = xyes && test x$enable_xml_docs = xyes])
+ [test x$enable_doxygen_docs = xyes && test x$enable_xml_docs = xyes &&
+ test x$enable_ducktype_docs = xyes])
#### Have to go $localstatedir->$prefix/var->/usr/local/var
@@ -1505,6 +1571,16 @@ if test "x$with_systemdsystemunitdir" != xno; then
fi
AM_CONDITIONAL(HAVE_SYSTEMD, [test "x$have_systemd" != "xno" -a -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ])
+AC_ARG_WITH([systemduserunitdir],
+AS_HELP_STRING([--with-systemduserunitdir=DIR], [Directory for systemd user service files]),
+ [],
+ [
+ PKG_CHECK_EXISTS([systemd],
+ [with_systemduserunitdir=$($PKG_CONFIG --variable=systemduserunitdir systemd)],
+ [with_systemduserunitdir='${libdir}/systemd/user'])
+ ])
+AC_SUBST([systemduserunitdir], [$with_systemduserunitdir])
+
##### Set up location for system bus socket
if ! test -z "$with_system_socket"; then
DBUS_SYSTEM_SOCKET=$with_system_socket
@@ -1574,6 +1650,13 @@ fi
AC_SUBST(DBUS_USER)
AC_DEFINE_UNQUOTED(DBUS_USER,"$DBUS_USER", [User for running the system BUS daemon])
+#### User for regression tests
+AS_IF([test -z "$with_test_user"], [with_test_user=nobody])
+DBUS_TEST_USER="$with_test_user"
+AC_SUBST([DBUS_TEST_USER])
+AC_DEFINE_UNQUOTED([DBUS_TEST_USER], ["$DBUS_TEST_USER"],
+ [Unprivileged user used in some regression tests])
+
#### Prefix to install into
DBUS_PREFIX=$EXPANDED_PREFIX
AC_SUBST(DBUS_PREFIX)
@@ -1587,10 +1670,13 @@ AC_DEFINE_UNQUOTED(DBUS_DATADIR,"$DBUS_DATADIR", [Directory for installing DBUS
#### Directory to install dbus-daemon
if test -z "$with_dbus_daemondir" ; then
DBUS_DAEMONDIR=$EXPANDED_BINDIR
+ dbus_daemondir='$bindir'
else
DBUS_DAEMONDIR=$with_dbus_daemondir
+ dbus_daemondir=$with_dbus_daemondir
fi
AC_SUBST(DBUS_DAEMONDIR)
+AC_SUBST(dbus_daemondir)
AC_DEFINE_UNQUOTED(DBUS_DAEMONDIR,"$DBUS_DAEMONDIR", [Directory for installing the DBUS daemon])
#### Directory to install the other binaries
@@ -1603,6 +1689,11 @@ DBUS_LIBEXECDIR="$EXPANDED_LIBEXECDIR"
AC_SUBST(DBUS_LIBEXECDIR)
AC_DEFINE_UNQUOTED(DBUS_LIBEXECDIR,"$DBUS_LIBEXECDIR", [Directory for installing the libexec binaries])
+#### Directory to source sysconfdir configuration from
+DBUS_SYSCONFDIR="$EXPANDED_SYSCONFDIR"
+AC_SUBST(DBUS_SYSCONFDIR)
+AC_DEFINE_UNQUOTED(DBUS_SYSCONFDIR,"$DBUS_SYSCONFDIR", [Directory to source sysconfdir configuration from])
+
#### Tell tests where to find certain stuff in builddir
DBUS_PWD=`pwd`
@@ -1740,26 +1831,40 @@ AH_VERBATIM(_DARWIN_ENVIRON,
])
AC_ARG_ENABLE([stats],
- [AS_HELP_STRING([--enable-stats],
- [enable bus daemon usage statistics])],
- [], [enable_stats=no])
+ [AS_HELP_STRING([--disable-stats],
+ [disable bus daemon usage statistics])],
+ [], [enable_stats=yes])
if test "x$enable_stats" = xyes; then
AC_DEFINE([DBUS_ENABLE_STATS], [1],
[Define to enable bus daemon usage statistics])
fi
+AC_ARG_ENABLE([user-session],
+ [AS_HELP_STRING([--enable-user-session],
+ [enable user-session semantics for session bus under systemd])],
+ [], [enable_user_session=no])
+AM_CONDITIONAL([DBUS_ENABLE_USER_SESSION],
+ [test "x$enable_user_session" = xyes])
+
AC_CONFIG_FILES([
Doxyfile
+dbus/Version
dbus/versioninfo.rc
dbus/dbus-arch-deps.h
bus/system.conf
bus/session.conf
+bus/legacy-config/system.conf
+bus/legacy-config/session.conf
+bus/example-system-enable-stats.conf
+bus/example-session-disable-stats.conf
bus/messagebus
bus/messagebus-config
bus/org.freedesktop.dbus-session.plist
bus/rc.messagebus
bus/dbus.service
bus/dbus.socket
+bus/systemd-user/dbus.service
+bus/systemd-user/dbus.socket
Makefile
dbus/Makefile
bus/Makefile
@@ -1773,27 +1878,11 @@ doc/dbus-launch.1.xml
doc/dbus-monitor.1.xml
doc/dbus-run-session.1.xml
doc/dbus-send.1.xml
+doc/dbus-test-tool.1.xml
+doc/dbus-update-activation-environment.1.xml
doc/dbus-uuidgen.1.xml
dbus-1.pc
dbus-1-uninstalled.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/incoming-limit.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
])
AC_OUTPUT
@@ -1819,7 +1908,9 @@ echo "
32-bit int: ${DBUS_INT32_TYPE}
16-bit int: ${DBUS_INT16_TYPE}
Doxygen: ${DOXYGEN:-not found}
- xmlto: ${XMLTO:-not found}"
+ xmlto: ${XMLTO:-not found}
+ ducktype: ${DUCKTYPE:-not found}
+ yelp-build: ${YELP_BUILD:-not found}"
echo "
Rebuilding generated files: ${USE_MAINTAINER_MODE}
@@ -1827,17 +1918,19 @@ echo "
Building embedded tests: ${enable_embedded_tests}
Building modular tests: ${enable_modular_tests}
- with GLib: ${with_glib}
- - with dbus-glib: ${with_dbus_glib}
+ Installing tests: ${enable_installed_tests}
Building verbose mode: ${enable_verbose_mode}
Building assertions: ${enable_asserts}
Building checks: ${enable_checks}
Building bus stats API: ${enable_stats}
Building SELinux support: ${have_selinux}
+ Building AppArmor support: ${have_apparmor}
Building inotify support: ${have_inotify}
Building kqueue support: ${have_kqueue}
Building systemd support: ${have_systemd}
Building X11 code: ${have_x11}
Building Doxygen docs: ${enable_doxygen_docs}
+ Building Ducktype docs: ${enable_ducktype_docs}
Building XML docs: ${enable_xml_docs}
Building launchd support: ${have_launchd}
Init scripts style: ${with_init_scripts}
diff --git a/dbus-1-uninstalled.pc.in b/dbus-1-uninstalled.pc.in
index 038c83e2..b66ad2f6 100644
--- a/dbus-1-uninstalled.pc.in
+++ b/dbus-1-uninstalled.pc.in
@@ -2,12 +2,15 @@ abs_top_builddir=@abs_top_builddir@
abs_top_srcdir=@abs_top_srcdir@
prefix=
exec_prefix=
+bindir=@bindir@
system_bus_default_address=@DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@
-sysconfdir=@EXPANDED_SYSCONFDIR@
-session_bus_services_dir=@EXPANDED_DATADIR@/dbus-1/services
-system_bus_services_dir=@EXPANDED_DATADIR@/dbus-1/system-services
-interfaces_dir=@EXPANDED_DATADIR@/dbus-1/interfaces
-daemondir=@DBUS_DAEMONDIR@
+datarootdir=@datarootdir@
+datadir=@datadir@
+sysconfdir=@sysconfdir@
+session_bus_services_dir=${datadir}/dbus-1/services
+system_bus_services_dir=${datadir}/dbus-1/system-services
+interfaces_dir=${datadir}/dbus-1/interfaces
+daemondir=@dbus_daemondir@
Name: dbus
Description: Free desktop message bus (uninstalled copy)
diff --git a/dbus-1.pc.in b/dbus-1.pc.in
index 25f8bcee..f93d1563 100644
--- a/dbus-1.pc.in
+++ b/dbus-1.pc.in
@@ -1,13 +1,16 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
+bindir=@bindir@
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
-system_bus_services_dir=@EXPANDED_DATADIR@/dbus-1/system-services
-interfaces_dir=@EXPANDED_DATADIR@/dbus-1/interfaces
-daemondir=@DBUS_DAEMONDIR@
+datarootdir=@datarootdir@
+datadir=@datadir@
+sysconfdir=@sysconfdir@
+session_bus_services_dir=${datadir}/dbus-1/services
+system_bus_services_dir=${datadir}/dbus-1/system-services
+interfaces_dir=${datadir}/dbus-1/interfaces
+daemondir=@dbus_daemondir@
Name: dbus
Description: Free desktop message bus
diff --git a/dbus/Makefile.am b/dbus/Makefile.am
index b2481073..a7b34917 100644
--- a/dbus/Makefile.am
+++ b/dbus/Makefile.am
@@ -1,20 +1,29 @@
-configdir=$(sysconfdir)/dbus-1
+dbusdatadir=$(datadir)/dbus-1
AM_CPPFLAGS = \
-I$(top_builddir) \
-I$(top_srcdir) \
+ $(DBUS_STATIC_BUILD_CPPFLAGS) \
$(SYSTEMD_CFLAGS) \
$(VALGRIND_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"\" \
+ -DDBUS_SYSTEM_CONFIG_FILE=\""$(dbusdatadir)/system.conf"\" \
+ -DDBUS_SESSION_CONFIG_FILE=\""$(dbusdatadir)/session.conf"\" \
$(NULL)
-# On Linux with glibc 2.17, sd-daemon.c support for POSIX message queues
-# results in an otherwise unnecessary dependency on librt. Disable it.
-AM_CPPFLAGS += -DSD_DAEMON_DISABLE_MQ
+AM_CFLAGS =
+
+if HAVE_VISIBILITY
+if !DBUS_WIN
+AM_CFLAGS += $(CFLAG_VISIBILITY)
+AM_CPPFLAGS += \
+ -DDBUS_EXPORT='__attribute__((__visibility__("default")))' \
+ -DDBUS_PRIVATE_EXPORT='__attribute__((__visibility__("default")))' \
+ $(NULL)
+endif
+endif
# if assertions are enabled, improve backtraces
AM_LDFLAGS = @R_DYNAMIC_LDFLAG@
@@ -46,9 +55,6 @@ else
dbus_res =
dbus_res_ldflag =
no_undefined =
-## don't export symbols that start with "_" (we use this
-## convention for internal symbols)
-export_symbols = -export-symbols-regex "^[^_].*"
intllibs = @LTLIBINTL@
@@ -108,8 +114,7 @@ DBUS_SHARED_arch_sources = \
dbus-transport-unix.h \
dbus-userdb.c \
dbus-userdb.h \
- sd-daemon.c \
- sd-daemon.h
+ $(NULL)
DBUS_UTIL_arch_sources = \
dbus-sysdeps-util-unix.c \
@@ -268,34 +273,33 @@ libdbus_1_la_SOURCES= \
$(DBUS_SHARED_SOURCES)
libdbus_internal_la_SOURCES= \
- $(DBUS_LIB_SOURCES) \
- $(DBUS_SHARED_SOURCES) \
$(DBUS_UTIL_SOURCES)
BUILT_SOURCES=$(nodist_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-internal.la
libdbus_1_la_CPPFLAGS = \
$(AM_CPPFLAGS) \
-Ddbus_1_EXPORTS \
$(NULL)
+
+if HAVE_LD_VERSION_SCRIPT
+SYMBOL_EXPORT_LDFLAGS=-Wl,--version-script=Version
+else
+SYMBOL_EXPORT_LDFLAGS=
+endif
+
libdbus_1_la_LIBADD= $(LIBDBUS_LIBS)
libdbus_1_la_LDFLAGS = \
$(AM_LDFLAGS) \
- $(export_symbols) \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ $(SYMBOL_EXPORT_LDFLAGS) \
-no-undefined \
$(NULL)
-libdbus_internal_la_CPPFLAGS = \
- $(AM_CPPFLAGS) \
- -DDBUS_STATIC_BUILD \
- $(NULL)
-libdbus_internal_la_LIBADD=$(LIBDBUS_LIBS) $(SYSTEMD_LIBS)
+libdbus_internal_la_LIBADD=$(LIBDBUS_LIBS) libdbus-1.la
if DBUS_WIN
# This must be a separate convenience library, otherwise libtool notices
@@ -305,7 +309,6 @@ if DBUS_WIN
noinst_LTLIBRARIES += libdbus-init-win.la
libdbus_init_win_la_SOURCES = dbus-init-win.cpp
libdbus_1_la_LIBADD += libdbus-init-win.la
-libdbus_internal_la_LIBADD += libdbus-init-win.la
endif
noinst_PROGRAMS =
@@ -323,7 +326,3 @@ test_dbus_LDADD = libdbus-internal.la
## mop up the gcov files
clean-local:
/bin/rm *.bb *.bbg *.da *.gcov .libs/*.da .libs/*.bbg || true
-
-update-systemd:
- curl http://cgit.freedesktop.org/systemd/systemd/plain/src/libsystemd-daemon/sd-daemon.c > $(srcdir)/sd-daemon.c
- curl http://cgit.freedesktop.org/systemd/systemd/plain/src/systemd/sd-daemon.h > $(srcdir)/sd-daemon.h
diff --git a/dbus/Version.in b/dbus/Version.in
new file mode 100644
index 00000000..f6cc3676
--- /dev/null
+++ b/dbus/Version.in
@@ -0,0 +1,10 @@
+LIBDBUS_1_@SOVERSION@ {
+ global:
+ dbus_*;
+ local:
+ *;
+};
+LIBDBUS_PRIVATE_@DBUS_VERSION@ {
+ global:
+ _dbus_*;
+};
diff --git a/dbus/dbus-asv-util.c b/dbus/dbus-asv-util.c
index 583e41fa..d3ac5e9c 100644
--- a/dbus/dbus-asv-util.c
+++ b/dbus/dbus-asv-util.c
@@ -258,3 +258,57 @@ _dbus_asv_add_string (DBusMessageIter *arr_iter,
return TRUE;
}
+
+/**
+ * Create a new entry in an a{sv} (map from string to variant)
+ * with a byte array value.
+ *
+ * If this function fails, the a{sv} must be abandoned, for instance
+ * with _dbus_asv_abandon().
+ *
+ * @param arr_iter the iterator which is appending to the array
+ * @param key a UTF-8 key for the map
+ * @param value the value
+ * @param n_elements the number of elements to append
+ * @returns #TRUE on success, or #FALSE if not enough memory
+ */
+dbus_bool_t
+_dbus_asv_add_byte_array (DBusMessageIter *arr_iter,
+ const char *key,
+ const void *value,
+ int n_elements)
+{
+ DBusMessageIter entry_iter;
+ DBusMessageIter var_iter;
+ DBusMessageIter byte_array_iter;
+
+ if (!_dbus_asv_open_entry (arr_iter, &entry_iter, key, "ay", &var_iter))
+ return FALSE;
+
+ if (!dbus_message_iter_open_container (&var_iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING,
+ &byte_array_iter))
+ {
+ _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter);
+ return FALSE;
+ }
+
+ if (!dbus_message_iter_append_fixed_array (&byte_array_iter, DBUS_TYPE_BYTE,
+ &value, n_elements))
+ {
+ dbus_message_iter_abandon_container (&var_iter, &byte_array_iter);
+ _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter);
+ return FALSE;
+ }
+
+ if (!dbus_message_iter_close_container (&var_iter, &byte_array_iter))
+ {
+ _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter);
+ return FALSE;
+ }
+
+ if (!_dbus_asv_close_entry (arr_iter, &entry_iter, &var_iter))
+ return FALSE;
+
+ return TRUE;
+}
diff --git a/dbus/dbus-asv-util.h b/dbus/dbus-asv-util.h
index 0337260a..277ab807 100644
--- a/dbus/dbus-asv-util.h
+++ b/dbus/dbus-asv-util.h
@@ -42,5 +42,9 @@ dbus_bool_t _dbus_asv_add_uint32 (DBusMessageIter *arr_iter,
dbus_bool_t _dbus_asv_add_string (DBusMessageIter *arr_iter,
const char *key,
const char *value);
+dbus_bool_t _dbus_asv_add_byte_array (DBusMessageIter *arr_iter,
+ const char *key,
+ const void *value,
+ int n_elements);
#endif
diff --git a/dbus/dbus-auth-script.c b/dbus/dbus-auth-script.c
index 164743b0..73872203 100644
--- a/dbus/dbus-auth-script.c
+++ b/dbus/dbus-auth-script.c
@@ -221,10 +221,15 @@ auth_set_unix_credentials(DBusAuth *auth,
_dbus_assert_not_reached ("no memory");
if (uid != DBUS_UID_UNSET)
- _dbus_credentials_add_unix_uid (credentials, uid);
+ {
+ if (!_dbus_credentials_add_unix_uid (credentials, uid))
+ _dbus_assert_not_reached ("no memory");
+ }
if (pid != DBUS_PID_UNSET)
- _dbus_credentials_add_pid (credentials, pid);
-
+ {
+ if (!_dbus_credentials_add_pid (credentials, pid))
+ _dbus_assert_not_reached ("no memory");
+ }
_dbus_auth_set_credentials (auth, credentials);
_dbus_credentials_unref (credentials);
@@ -527,7 +532,7 @@ _dbus_auth_script_run (const DBusString *filename)
goto out;
}
- _dbus_string_delete (&to_send, where, strlen ("USERID_HEX"));
+ _dbus_string_delete (&to_send, where, (int) strlen ("USERID_HEX"));
if (!_dbus_string_hex_encode (&username, 0,
&to_send, where))
@@ -560,7 +565,7 @@ _dbus_auth_script_run (const DBusString *filename)
goto out;
}
- _dbus_string_delete (&to_send, where, strlen ("USERNAME_HEX"));
+ _dbus_string_delete (&to_send, where, (int) strlen ("USERNAME_HEX"));
if (!_dbus_string_hex_encode (&username, 0,
&to_send, where))
diff --git a/dbus/dbus-auth-util.c b/dbus/dbus-auth-util.c
index e88d6696..10cbc490 100644
--- a/dbus/dbus-auth-util.c
+++ b/dbus/dbus-auth-util.c
@@ -34,7 +34,6 @@
/** @} */
#ifdef DBUS_ENABLE_EMBEDDED_TESTS
-#include "dbus-test.h"
#include "dbus-auth-script.h"
#include <stdio.h>
diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c
index 6a07665f..f2227875 100644
--- a/dbus/dbus-auth.c
+++ b/dbus/dbus-auth.c
@@ -37,7 +37,7 @@
* @brief DBusAuth object
*
* DBusAuth manages the authentication negotiation when a connection
- * is first established, and also manage any encryption used over a
+ * is first established, and also manages any encryption used over a
* connection.
*
* @todo some SASL profiles require sending the empty string as a
@@ -524,10 +524,8 @@ sha1_handle_first_client_response (DBusAuth *auth,
*/
DBusString tmp;
DBusString tmp2;
- dbus_bool_t retval;
- DBusError error;
-
- retval = FALSE;
+ dbus_bool_t retval = FALSE;
+ DBusError error = DBUS_ERROR_INIT;
_dbus_string_set_length (&auth->challenge, 0);
@@ -578,7 +576,6 @@ sha1_handle_first_client_response (DBusAuth *auth,
if (auth->keyring == NULL)
{
- dbus_error_init (&error);
auth->keyring = _dbus_keyring_new_for_credentials (auth->desired_identity,
&auth->context,
&error);
@@ -610,7 +607,6 @@ sha1_handle_first_client_response (DBusAuth *auth,
_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)
{
@@ -640,8 +636,25 @@ sha1_handle_first_client_response (DBusAuth *auth,
if (!_dbus_string_append (&tmp2, " "))
goto out;
- if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
- goto out;
+ if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES, &error))
+ {
+ 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 generating challenge: %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;
+ }
+ }
_dbus_string_set_length (&auth->challenge, 0);
if (!_dbus_string_hex_encode (&tmp, 0, &auth->challenge, 0))
@@ -826,7 +839,7 @@ handle_client_data_cookie_sha1_mech (DBusAuth *auth,
* 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;
+ dbus_bool_t retval = FALSE;
DBusString context;
DBusString cookie_id_str;
DBusString server_challenge;
@@ -835,9 +848,8 @@ handle_client_data_cookie_sha1_mech (DBusAuth *auth,
DBusString tmp;
int i, j;
long val;
-
- retval = FALSE;
-
+ DBusError error = DBUS_ERROR_INIT;
+
if (!_dbus_string_find_blank (data, 0, &i))
{
if (send_error (auth,
@@ -903,9 +915,6 @@ handle_client_data_cookie_sha1_mech (DBusAuth *auth,
if (auth->keyring == NULL)
{
- DBusError error;
-
- dbus_error_init (&error);
auth->keyring = _dbus_keyring_new_for_credentials (NULL,
&context,
&error);
@@ -942,9 +951,28 @@ handle_client_data_cookie_sha1_mech (DBusAuth *auth,
if (!_dbus_string_init (&tmp))
goto out_3;
-
- if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
- goto out_4;
+
+ if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES, &error))
+ {
+ if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
+ {
+ dbus_error_free (&error);
+ goto out_4;
+ }
+ else
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (&error);
+
+ _dbus_verbose ("%s: Failed to generate challenge: %s\n",
+ DBUS_AUTH_NAME (auth), error.message);
+
+ if (send_error (auth, "Failed to generate challenge"))
+ retval = TRUE; /* retval is only about mem */
+
+ dbus_error_free (&error);
+ goto out_4;
+ }
+ }
if (!_dbus_string_init (&client_challenge))
goto out_4;
@@ -1102,20 +1130,23 @@ handle_server_data_external_mech (DBusAuth *auth,
auth->desired_identity))
return FALSE;
- /* also copy process ID from the socket credentials
+ /* also copy misc process info 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 (!_dbus_credentials_add_credential (auth->authorized_identity,
+ DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
+ auth->credentials))
+ return FALSE;
+
if (!send_ok (auth))
return FALSE;
diff --git a/dbus/dbus-auth.h b/dbus/dbus-auth.h
index ba1975f7..e0323023 100644
--- a/dbus/dbus-auth.h
+++ b/dbus/dbus-auth.h
@@ -41,23 +41,35 @@ typedef enum
DBUS_AUTH_STATE_AUTHENTICATED
} DBusAuthState;
+DBUS_PRIVATE_EXPORT
DBusAuth* _dbus_auth_server_new (const DBusString *guid);
+DBUS_PRIVATE_EXPORT
DBusAuth* _dbus_auth_client_new (void);
+DBUS_PRIVATE_EXPORT
DBusAuth* _dbus_auth_ref (DBusAuth *auth);
+DBUS_PRIVATE_EXPORT
void _dbus_auth_unref (DBusAuth *auth);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_auth_set_mechanisms (DBusAuth *auth,
const char **mechanisms);
+DBUS_PRIVATE_EXPORT
DBusAuthState _dbus_auth_do_work (DBusAuth *auth);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_auth_get_bytes_to_send (DBusAuth *auth,
const DBusString **str);
+DBUS_PRIVATE_EXPORT
void _dbus_auth_bytes_sent (DBusAuth *auth,
int bytes_sent);
+DBUS_PRIVATE_EXPORT
void _dbus_auth_get_buffer (DBusAuth *auth,
DBusString **buffer);
+DBUS_PRIVATE_EXPORT
void _dbus_auth_return_buffer (DBusAuth *auth,
DBusString *buffer);
+DBUS_PRIVATE_EXPORT
void _dbus_auth_get_unused_bytes (DBusAuth *auth,
const DBusString **str);
+DBUS_PRIVATE_EXPORT
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,
@@ -67,9 +79,12 @@ dbus_bool_t _dbus_auth_needs_decoding (DBusAuth *auth);
dbus_bool_t _dbus_auth_decode_data (DBusAuth *auth,
const DBusString *encoded,
DBusString *plaintext);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_auth_set_credentials (DBusAuth *auth,
DBusCredentials *credentials);
+DBUS_PRIVATE_EXPORT
DBusCredentials* _dbus_auth_get_identity (DBusAuth *auth);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_auth_set_context (DBusAuth *auth,
const DBusString *context);
const char* _dbus_auth_get_guid_from_server(DBusAuth *auth);
diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h
index 28974040..48357321 100644
--- a/dbus/dbus-connection-internal.h
+++ b/dbus/dbus-connection-internal.h
@@ -46,9 +46,13 @@ typedef enum
typedef void (* DBusPendingFdsChangeFunction) (void *data);
+DBUS_PRIVATE_EXPORT
void _dbus_connection_lock (DBusConnection *connection);
+DBUS_PRIVATE_EXPORT
void _dbus_connection_unlock (DBusConnection *connection);
+DBUS_PRIVATE_EXPORT
DBusConnection * _dbus_connection_ref_unlocked (DBusConnection *connection);
+DBUS_PRIVATE_EXPORT
void _dbus_connection_unref_unlocked (DBusConnection *connection);
void _dbus_connection_queue_received_message_link (DBusConnection *connection,
DBusList *link);
@@ -96,18 +100,26 @@ dbus_bool_t _dbus_connection_send_and_unlock (DBusConnection
void _dbus_connection_queue_synthesized_message_link (DBusConnection *connection,
DBusList *link);
+DBUS_PRIVATE_EXPORT
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);
+DBUS_PRIVATE_EXPORT
int _dbus_connection_get_pending_fds_count (DBusConnection *connection);
+DBUS_PRIVATE_EXPORT
void _dbus_connection_set_pending_fds_function (DBusConnection *connection,
DBusPendingFdsChangeFunction callback,
void *data);
+DBUS_PRIVATE_EXPORT
+dbus_bool_t _dbus_connection_get_linux_security_label (DBusConnection *connection,
+ char **label_p);
+
/* if DBUS_ENABLE_STATS */
+DBUS_PRIVATE_EXPORT
void _dbus_connection_get_stats (DBusConnection *connection,
dbus_uint32_t *in_messages,
dbus_uint32_t *in_bytes,
diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
index b574207d..81b3a838 100644
--- a/dbus/dbus-connection.c
+++ b/dbus/dbus-connection.c
@@ -4436,15 +4436,24 @@ _dbus_connection_peer_filter_unlocked_no_update (DBusConnection *connection,
"GetMachineId"))
{
DBusString uuid;
-
- ret = dbus_message_new_method_return (message);
- if (ret == NULL)
+ DBusError error = DBUS_ERROR_INIT;
+
+ if (!_dbus_string_init (&uuid))
goto out;
- _dbus_string_init (&uuid);
- if (_dbus_get_local_machine_uuid_encoded (&uuid))
+ if (_dbus_get_local_machine_uuid_encoded (&uuid, &error))
{
- const char *v_STRING = _dbus_string_get_const_data (&uuid);
+ const char *v_STRING;
+
+ ret = dbus_message_new_method_return (message);
+
+ if (ret == NULL)
+ {
+ _dbus_string_free (&uuid);
+ goto out;
+ }
+
+ v_STRING = _dbus_string_get_const_data (&uuid);
if (dbus_message_append_args (ret,
DBUS_TYPE_STRING, &v_STRING,
DBUS_TYPE_INVALID))
@@ -4452,6 +4461,23 @@ _dbus_connection_peer_filter_unlocked_no_update (DBusConnection *connection,
sent = _dbus_connection_send_unlocked_no_update (connection, ret, NULL);
}
}
+ else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
+ {
+ dbus_error_free (&error);
+ goto out;
+ }
+ else
+ {
+ ret = dbus_message_new_error (message, error.name, error.message);
+ dbus_error_free (&error);
+
+ if (ret == NULL)
+ goto out;
+
+ sent = _dbus_connection_send_unlocked_no_update (connection, ret,
+ NULL);
+ }
+
_dbus_string_free (&uuid);
}
else
@@ -5149,14 +5175,19 @@ dbus_connection_get_socket(DBusConnection *connection,
int *fd)
{
dbus_bool_t retval;
+ DBusSocket s = DBUS_SOCKET_INIT;
_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);
+ retval = _dbus_transport_get_socket_fd (connection->transport, &s);
+
+ if (retval)
+ {
+ *fd = _dbus_socket_get_int (s);
+ }
CONNECTION_UNLOCK (connection);
@@ -5322,6 +5353,32 @@ dbus_connection_set_unix_user_function (DBusConnection *connection,
(* old_free_function) (old_data);
}
+/* Same calling convention as dbus_connection_get_windows_user */
+dbus_bool_t
+_dbus_connection_get_linux_security_label (DBusConnection *connection,
+ char **label_p)
+{
+ dbus_bool_t result;
+
+ _dbus_assert (connection != NULL);
+ _dbus_assert (label_p != NULL);
+
+ CONNECTION_LOCK (connection);
+
+ if (!_dbus_transport_try_to_authenticate (connection->transport))
+ result = FALSE;
+ else
+ result = _dbus_transport_get_linux_security_label (connection->transport,
+ label_p);
+#ifndef __linux__
+ _dbus_assert (!result);
+#endif
+
+ CONNECTION_UNLOCK (connection);
+
+ return result;
+}
+
/**
* Gets the Windows user SID of the connection if known. Returns
* #TRUE if the ID is filled in. Always returns #FALSE on non-Windows
diff --git a/dbus/dbus-credentials-util.c b/dbus/dbus-credentials-util.c
index d2d164f7..94d72014 100644
--- a/dbus/dbus-credentials-util.c
+++ b/dbus/dbus-credentials-util.c
@@ -34,7 +34,6 @@
/** @} */
#ifdef DBUS_ENABLE_EMBEDDED_TESTS
-#include "dbus-test.h"
#include <stdio.h>
#include <string.h>
diff --git a/dbus/dbus-credentials.c b/dbus/dbus-credentials.c
index 7325125c..151bb00f 100644
--- a/dbus/dbus-credentials.c
+++ b/dbus/dbus-credentials.c
@@ -50,6 +50,7 @@ struct DBusCredentials {
dbus_uid_t unix_uid;
dbus_pid_t pid;
char *windows_sid;
+ char *linux_security_label;
void *adt_audit_data;
dbus_int32_t adt_audit_data_size;
};
@@ -79,6 +80,7 @@ _dbus_credentials_new (void)
creds->unix_uid = DBUS_UID_UNSET;
creds->pid = DBUS_PID_UNSET;
creds->windows_sid = NULL;
+ creds->linux_security_label = NULL;
creds->adt_audit_data = NULL;
creds->adt_audit_data_size = 0;
@@ -133,6 +135,7 @@ _dbus_credentials_unref (DBusCredentials *credentials)
if (credentials->refcount == 0)
{
dbus_free (credentials->windows_sid);
+ dbus_free (credentials->linux_security_label);
dbus_free (credentials->adt_audit_data);
dbus_free (credentials);
}
@@ -193,6 +196,30 @@ _dbus_credentials_add_windows_sid (DBusCredentials *credentials,
}
/**
+ * Add a Linux security label, as used by LSMs such as SELinux, Smack and
+ * AppArmor, to the credentials.
+ *
+ * @param credentials the object
+ * @param label the label
+ * @returns #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_credentials_add_linux_security_label (DBusCredentials *credentials,
+ const char *label)
+{
+ char *copy;
+
+ copy = _dbus_strdup (label);
+ if (copy == NULL)
+ return FALSE;
+
+ dbus_free (credentials->linux_security_label);
+ credentials->linux_security_label = copy;
+
+ return TRUE;
+}
+
+/**
* Add ADT audit data to the credentials.
*
* @param credentials the object
@@ -236,6 +263,8 @@ _dbus_credentials_include (DBusCredentials *credentials,
return credentials->unix_uid != DBUS_UID_UNSET;
case DBUS_CREDENTIAL_WINDOWS_SID:
return credentials->windows_sid != NULL;
+ case DBUS_CREDENTIAL_LINUX_SECURITY_LABEL:
+ return credentials->linux_security_label != NULL;
case DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID:
return credentials->adt_audit_data != NULL;
}
@@ -284,6 +313,19 @@ _dbus_credentials_get_windows_sid (DBusCredentials *credentials)
}
/**
+ * Gets the Linux security label (as used by LSMs) from the credentials,
+ * or #NULL if the credentials object doesn't contain a security label.
+ *
+ * @param credentials the object
+ * @returns the security label
+ */
+const char *
+_dbus_credentials_get_linux_security_label (DBusCredentials *credentials)
+{
+ return credentials->linux_security_label;
+}
+
+/**
* Gets the ADT audit data in the credentials, or #NULL if
* the credentials object doesn't contain ADT audit data.
*
@@ -329,6 +371,10 @@ _dbus_credentials_are_superset (DBusCredentials *credentials,
(possible_subset->windows_sid == NULL ||
(credentials->windows_sid && strcmp (possible_subset->windows_sid,
credentials->windows_sid) == 0)) &&
+ (possible_subset->linux_security_label == NULL ||
+ (credentials->linux_security_label != NULL &&
+ strcmp (possible_subset->linux_security_label,
+ credentials->linux_security_label) == 0)) &&
(possible_subset->adt_audit_data == NULL ||
(credentials->adt_audit_data && memcmp (possible_subset->adt_audit_data,
credentials->adt_audit_data,
@@ -348,6 +394,7 @@ _dbus_credentials_are_empty (DBusCredentials *credentials)
credentials->pid == DBUS_PID_UNSET &&
credentials->unix_uid == DBUS_UID_UNSET &&
credentials->windows_sid == NULL &&
+ credentials->linux_security_label == NULL &&
credentials->adt_audit_data == NULL;
}
@@ -388,6 +435,9 @@ _dbus_credentials_add_credentials (DBusCredentials *credentials,
DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
other_credentials) &&
_dbus_credentials_add_credential (credentials,
+ DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
+ other_credentials) &&
+ _dbus_credentials_add_credential (credentials,
DBUS_CREDENTIAL_WINDOWS_SID,
other_credentials);
}
@@ -427,6 +477,13 @@ _dbus_credentials_add_credential (DBusCredentials *credentials,
if (!_dbus_credentials_add_windows_sid (credentials, other_credentials->windows_sid))
return FALSE;
}
+ else if (which == DBUS_CREDENTIAL_LINUX_SECURITY_LABEL &&
+ other_credentials->linux_security_label != NULL)
+ {
+ if (!_dbus_credentials_add_linux_security_label (credentials,
+ other_credentials->linux_security_label))
+ return FALSE;
+ }
else if (which == DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID &&
other_credentials->adt_audit_data != NULL)
{
@@ -449,6 +506,8 @@ _dbus_credentials_clear (DBusCredentials *credentials)
credentials->unix_uid = DBUS_UID_UNSET;
dbus_free (credentials->windows_sid);
credentials->windows_sid = NULL;
+ dbus_free (credentials->linux_security_label);
+ credentials->linux_security_label = NULL;
dbus_free (credentials->adt_audit_data);
credentials->adt_audit_data = NULL;
credentials->adt_audit_data_size = 0;
@@ -540,6 +599,15 @@ _dbus_credentials_to_string_append (DBusCredentials *credentials,
else
join = FALSE;
+ if (credentials->linux_security_label != NULL)
+ {
+ if (!_dbus_string_append_printf (string, "%slsm='%s'",
+ join ? " " : "",
+ credentials->linux_security_label))
+ goto oom;
+ join = TRUE;
+ }
+
return TRUE;
oom:
return FALSE;
diff --git a/dbus/dbus-credentials.h b/dbus/dbus-credentials.h
index abcc4bb3..6bf6c2b1 100644
--- a/dbus/dbus-credentials.h
+++ b/dbus/dbus-credentials.h
@@ -34,32 +34,50 @@ typedef enum {
DBUS_CREDENTIAL_UNIX_PROCESS_ID,
DBUS_CREDENTIAL_UNIX_USER_ID,
DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
+ DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
DBUS_CREDENTIAL_WINDOWS_SID
} DBusCredentialType;
+DBUS_PRIVATE_EXPORT
DBusCredentials* _dbus_credentials_new_from_current_process (void);
+DBUS_PRIVATE_EXPORT
DBusCredentials* _dbus_credentials_new (void);
+DBUS_PRIVATE_EXPORT
void _dbus_credentials_ref (DBusCredentials *credentials);
+DBUS_PRIVATE_EXPORT
void _dbus_credentials_unref (DBusCredentials *credentials);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_credentials_add_pid (DBusCredentials *credentials,
dbus_pid_t pid);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_credentials_add_unix_uid (DBusCredentials *credentials,
dbus_uid_t uid);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_credentials_add_windows_sid (DBusCredentials *credentials,
const char *windows_sid);
+dbus_bool_t _dbus_credentials_add_linux_security_label (DBusCredentials *credentials,
+ const char *label);
dbus_bool_t _dbus_credentials_add_adt_audit_data (DBusCredentials *credentials,
void *audit_data,
dbus_int32_t size);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_credentials_include (DBusCredentials *credentials,
DBusCredentialType type);
+DBUS_PRIVATE_EXPORT
dbus_pid_t _dbus_credentials_get_pid (DBusCredentials *credentials);
+DBUS_PRIVATE_EXPORT
dbus_uid_t _dbus_credentials_get_unix_uid (DBusCredentials *credentials);
+DBUS_PRIVATE_EXPORT
const char* _dbus_credentials_get_windows_sid (DBusCredentials *credentials);
+const char * _dbus_credentials_get_linux_security_label (DBusCredentials *credentials);
void * _dbus_credentials_get_adt_audit_data (DBusCredentials *credentials);
dbus_int32_t _dbus_credentials_get_adt_audit_data_size (DBusCredentials *credentials);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_credentials_are_superset (DBusCredentials *credentials,
DBusCredentials *possible_subset);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_credentials_are_empty (DBusCredentials *credentials);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_credentials_are_anonymous (DBusCredentials *credentials);
dbus_bool_t _dbus_credentials_add_credentials (DBusCredentials *credentials,
DBusCredentials *other_credentials);
@@ -67,10 +85,14 @@ dbus_bool_t _dbus_credentials_add_credentials (DBusCredentials
dbus_bool_t _dbus_credentials_add_credential (DBusCredentials *credentials,
DBusCredentialType which,
DBusCredentials *other_credentials);
+DBUS_PRIVATE_EXPORT
void _dbus_credentials_clear (DBusCredentials *credentials);
+DBUS_PRIVATE_EXPORT
DBusCredentials* _dbus_credentials_copy (DBusCredentials *credentials);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_credentials_same_user (DBusCredentials *credentials,
DBusCredentials *other_credentials);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_credentials_to_string_append (DBusCredentials *credentials,
DBusString *string);
diff --git a/dbus/dbus-errors.c b/dbus/dbus-errors.c
index a0571a50..5a305ca0 100644
--- a/dbus/dbus-errors.c
+++ b/dbus/dbus-errors.c
@@ -189,9 +189,9 @@ dbus_error_init (DBusError *error)
{
DBusRealError *real;
- _dbus_return_if_fail (error != NULL);
+ _DBUS_STATIC_ASSERT (sizeof (DBusError) == sizeof (DBusRealError));
- _dbus_assert (sizeof (DBusError) == sizeof (DBusRealError));
+ _dbus_return_if_fail (error != NULL);
real = (DBusRealError *)error;
@@ -356,8 +356,6 @@ dbus_set_error (DBusError *error,
const char *format,
...)
{
- DBusRealError *real;
- DBusString str;
va_list args;
if (error == NULL)
@@ -366,7 +364,26 @@ dbus_set_error (DBusError *error,
/* it's a bug to pile up errors */
_dbus_return_if_error_is_set (error);
_dbus_return_if_fail (name != NULL);
-
+
+ va_start (args, format);
+ _dbus_set_error_valist (error, name, format, args);
+ va_end (args);
+}
+
+void
+_dbus_set_error_valist (DBusError *error,
+ const char *name,
+ const char *format,
+ va_list args)
+{
+ DBusRealError *real;
+ DBusString str;
+
+ _dbus_assert (name != NULL);
+
+ if (error == NULL)
+ return;
+
_dbus_assert (error->name == NULL);
_dbus_assert (error->message == NULL);
@@ -384,14 +401,11 @@ dbus_set_error (DBusError *error,
}
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;
diff --git a/dbus/dbus-file-unix.c b/dbus/dbus-file-unix.c
index 19759336..830d3fe4 100644
--- a/dbus/dbus-file-unix.c
+++ b/dbus/dbus-file-unix.c
@@ -202,9 +202,9 @@ _dbus_string_save_to_file (const DBusString *str,
}
#define N_TMP_FILENAME_RANDOM_BYTES 8
- if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES))
+ if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES,
+ error))
{
- dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
_dbus_string_free (&tmp_filename);
return FALSE;
}
diff --git a/dbus/dbus-file-win.c b/dbus/dbus-file-win.c
index 06a8ea1c..0dbe11ec 100644
--- a/dbus/dbus-file-win.c
+++ b/dbus/dbus-file-win.c
@@ -251,9 +251,9 @@ _dbus_string_save_to_file (const DBusString *str,
}
#define N_TMP_FILENAME_RANDOM_BYTES 8
- if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES))
+ if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES,
+ error))
{
- dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
_dbus_string_free (&tmp_filename);
return FALSE;
}
diff --git a/dbus/dbus-file.h b/dbus/dbus-file.h
index 24837f47..4fa30cde 100644
--- a/dbus/dbus-file.h
+++ b/dbus/dbus-file.h
@@ -40,6 +40,7 @@ DBUS_BEGIN_DECLS
* File interface
*/
dbus_bool_t _dbus_file_exists (const char *file);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_file_get_contents (DBusString *str,
const DBusString *filename,
DBusError *error);
@@ -53,6 +54,7 @@ dbus_bool_t _dbus_make_file_world_readable (const DBusString *filename,
dbus_bool_t _dbus_create_file_exclusively (const DBusString *filename,
DBusError *error);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_delete_file (const DBusString *filename,
DBusError *error);
diff --git a/dbus/dbus-hash.c b/dbus/dbus-hash.c
index c80835aa..8f7d04bb 100644
--- a/dbus/dbus-hash.c
+++ b/dbus/dbus-hash.c
@@ -519,7 +519,7 @@ _dbus_hash_iter_init (DBusHashTable *table,
{
DBusRealHashIter *real;
- _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
+ _DBUS_STATIC_ASSERT (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
real = (DBusRealHashIter*) iter;
@@ -544,7 +544,7 @@ _dbus_hash_iter_next (DBusHashIter *iter)
{
DBusRealHashIter *real;
- _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
+ _DBUS_STATIC_ASSERT (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
real = (DBusRealHashIter*) iter;
@@ -746,7 +746,7 @@ _dbus_hash_iter_lookup (DBusHashTable *table,
DBusHashEntry *entry;
DBusHashEntry **bucket;
- _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
+ _DBUS_STATIC_ASSERT (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
real = (DBusRealHashIter*) iter;
diff --git a/dbus/dbus-hash.h b/dbus/dbus-hash.h
index 5aa183c4..2898f51c 100644
--- a/dbus/dbus-hash.h
+++ b/dbus/dbus-hash.h
@@ -71,47 +71,66 @@ typedef enum
DBUS_HASH_UINTPTR /**< Hash keys are integer capable to hold a pointer. */
} DBusHashType;
+DBUS_PRIVATE_EXPORT
DBusHashTable* _dbus_hash_table_new (DBusHashType type,
DBusFreeFunction key_free_function,
DBusFreeFunction value_free_function);
DBusHashTable* _dbus_hash_table_ref (DBusHashTable *table);
+DBUS_PRIVATE_EXPORT
void _dbus_hash_table_unref (DBusHashTable *table);
void _dbus_hash_table_remove_all (DBusHashTable *table);
+DBUS_PRIVATE_EXPORT
void _dbus_hash_iter_init (DBusHashTable *table,
DBusHashIter *iter);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_hash_iter_next (DBusHashIter *iter);
+DBUS_PRIVATE_EXPORT
void _dbus_hash_iter_remove_entry (DBusHashIter *iter);
+DBUS_PRIVATE_EXPORT
void* _dbus_hash_iter_get_value (DBusHashIter *iter);
void _dbus_hash_iter_set_value (DBusHashIter *iter,
void *value);
+DBUS_PRIVATE_EXPORT
int _dbus_hash_iter_get_int_key (DBusHashIter *iter);
+DBUS_PRIVATE_EXPORT
const char* _dbus_hash_iter_get_string_key (DBusHashIter *iter);
+DBUS_PRIVATE_EXPORT
uintptr_t _dbus_hash_iter_get_uintptr_key (DBusHashIter *iter);
dbus_bool_t _dbus_hash_iter_lookup (DBusHashTable *table,
void *key,
dbus_bool_t create_if_not_found,
DBusHashIter *iter);
+DBUS_PRIVATE_EXPORT
void* _dbus_hash_table_lookup_string (DBusHashTable *table,
const char *key);
+DBUS_PRIVATE_EXPORT
void* _dbus_hash_table_lookup_int (DBusHashTable *table,
int key);
+DBUS_PRIVATE_EXPORT
void* _dbus_hash_table_lookup_uintptr (DBusHashTable *table,
uintptr_t key);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_hash_table_remove_string (DBusHashTable *table,
const char *key);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_hash_table_remove_int (DBusHashTable *table,
int key);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_hash_table_remove_uintptr (DBusHashTable *table,
uintptr_t key);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_hash_table_insert_string (DBusHashTable *table,
char *key,
void *value);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_hash_table_insert_int (DBusHashTable *table,
int key,
void *value);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_hash_table_insert_uintptr (DBusHashTable *table,
uintptr_t key,
void *value);
+DBUS_PRIVATE_EXPORT
int _dbus_hash_table_get_n_entries (DBusHashTable *table);
/* Preallocation */
@@ -119,14 +138,70 @@ int _dbus_hash_table_get_n_entries (DBusHashTable *table);
/** A preallocated hash entry */
typedef struct DBusPreallocatedHash DBusPreallocatedHash;
+DBUS_PRIVATE_EXPORT
DBusPreallocatedHash *_dbus_hash_table_preallocate_entry (DBusHashTable *table);
+DBUS_PRIVATE_EXPORT
void _dbus_hash_table_free_preallocated_entry (DBusHashTable *table,
DBusPreallocatedHash *preallocated);
+DBUS_PRIVATE_EXPORT
void _dbus_hash_table_insert_string_preallocated (DBusHashTable *table,
DBusPreallocatedHash *preallocated,
char *key,
void *value);
+#ifdef DBUS_WIN
+# define DBUS_HASH_POLLABLE DBUS_HASH_UINTPTR
+#else
+# define DBUS_HASH_POLLABLE DBUS_HASH_INT
+#endif
+
+static inline DBusPollable
+_dbus_hash_iter_get_pollable_key (DBusHashIter *iter)
+{
+#ifdef DBUS_WIN
+ DBusSocket s;
+
+ s.sock = _dbus_hash_iter_get_uintptr_key (iter);
+ return s;
+#else
+ return _dbus_hash_iter_get_int_key (iter);
+#endif
+}
+
+static inline void *
+_dbus_hash_table_lookup_pollable (DBusHashTable *table,
+ DBusPollable key)
+{
+#ifdef DBUS_WIN
+ return _dbus_hash_table_lookup_uintptr (table, key.sock);
+#else
+ return _dbus_hash_table_lookup_int (table, key);
+#endif
+}
+
+static inline dbus_bool_t
+_dbus_hash_table_remove_pollable (DBusHashTable *table,
+ DBusPollable key)
+{
+#ifdef DBUS_WIN
+ return _dbus_hash_table_remove_uintptr (table, key.sock);
+#else
+ return _dbus_hash_table_remove_int (table, key);
+#endif
+}
+
+static inline dbus_bool_t
+_dbus_hash_table_insert_pollable (DBusHashTable *table,
+ DBusPollable key,
+ void *value)
+{
+#ifdef DBUS_WIN
+ return _dbus_hash_table_insert_uintptr (table, key.sock, value);
+#else
+ return _dbus_hash_table_insert_int (table, key, value);
+#endif
+}
+
/** @} */
DBUS_END_DECLS
diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c
index 9c8bc529..30a5fa73 100644
--- a/dbus/dbus-internals.c
+++ b/dbus/dbus-internals.c
@@ -363,6 +363,16 @@ _dbus_is_verbose_real (void)
return verbose;
}
+void _dbus_set_verbose (dbus_bool_t state)
+{
+ verbose = state;
+}
+
+dbus_bool_t _dbus_get_verbose (void)
+{
+ return verbose;
+}
+
/**
* Prints a warning message to stderr
* if the user has enabled verbose mode.
@@ -636,12 +646,18 @@ _dbus_string_array_contains (const char **array,
* there's some text about it in the spec that should also change.
*
* @param uuid the uuid to initialize
+ * @param error location to store reason for failure
+ * @returns #TRUE on success
*/
-void
-_dbus_generate_uuid (DBusGUID *uuid)
+dbus_bool_t
+_dbus_generate_uuid (DBusGUID *uuid,
+ DBusError *error)
{
+ DBusError rand_error;
long now;
+ dbus_error_init (&rand_error);
+
/* don't use monotonic time because the UUID may be saved to disk, e.g.
* it may persist across reboots
*/
@@ -649,7 +665,17 @@ _dbus_generate_uuid (DBusGUID *uuid)
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);
+ if (!_dbus_generate_random_bytes_buffer (uuid->as_bytes,
+ DBUS_UUID_LENGTH_BYTES - 4,
+ &rand_error))
+ {
+ dbus_set_error (error, rand_error.name,
+ "Failed to generate UUID: %s", rand_error.message);
+ dbus_error_free (&rand_error);
+ return FALSE;
+ }
+
+ return TRUE;
}
/**
@@ -831,7 +857,10 @@ _dbus_read_uuid_file (const DBusString *filename,
else
{
dbus_error_free (&read_error);
- _dbus_generate_uuid (uuid);
+
+ if (!_dbus_generate_uuid (uuid, error))
+ return FALSE;
+
return _dbus_write_uuid_file (filename, uuid, error);
}
}
@@ -848,22 +877,27 @@ static DBusGUID machine_uuid;
* machine is reconfigured or its hardware is modified.
*
* @param uuid_str string to append hex-encoded machine uuid to
- * @returns #FALSE if no memory
+ * @param error location to store reason for failure
+ * @returns #TRUE if successful
*/
dbus_bool_t
-_dbus_get_local_machine_uuid_encoded (DBusString *uuid_str)
+_dbus_get_local_machine_uuid_encoded (DBusString *uuid_str,
+ DBusError *error)
{
- dbus_bool_t ok;
+ dbus_bool_t ok = TRUE;
if (!_DBUS_LOCK (machine_uuid))
- return FALSE;
+ {
+ _DBUS_SET_OOM (error);
+ return FALSE;
+ }
if (machine_uuid_initialized_generation != _dbus_current_generation)
{
- DBusError error = DBUS_ERROR_INIT;
+ DBusError local_error = DBUS_ERROR_INIT;
if (!_dbus_read_local_machine_uuid (&machine_uuid, FALSE,
- &error))
+ &local_error))
{
#ifndef DBUS_ENABLE_EMBEDDED_TESTS
/* For the test suite, we may not be installed so just continue silently
@@ -872,16 +906,23 @@ _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str)
*/
_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);
+ local_error.message);
#endif
- dbus_error_free (&error);
+ dbus_error_free (&local_error);
- _dbus_generate_uuid (&machine_uuid);
+ ok = _dbus_generate_uuid (&machine_uuid, error);
}
}
- ok = _dbus_uuid_encode (&machine_uuid, uuid_str);
+ if (ok)
+ {
+ if (!_dbus_uuid_encode (&machine_uuid, uuid_str))
+ {
+ ok = FALSE;
+ _DBUS_SET_OOM (error);
+ }
+ }
_DBUS_UNLOCK (machine_uuid);
diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h
index 4658b67b..3eb8749f 100644
--- a/dbus/dbus-internals.h
+++ b/dbus/dbus-internals.h
@@ -35,9 +35,11 @@
DBUS_BEGIN_DECLS
+DBUS_PRIVATE_EXPORT
void _dbus_warn (const char *format,
...) _DBUS_GNUC_PRINTF (1, 2);
+DBUS_PRIVATE_EXPORT
void _dbus_warn_check_failed (const char *format,
...) _DBUS_GNUC_PRINTF (1, 2);
@@ -89,16 +91,24 @@ void _dbus_warn_check_failed (const char *format,
#endif
#ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
+DBUS_PRIVATE_EXPORT
void _dbus_verbose_real (const char *file, const int line, const char *function,
const char *format,...) _DBUS_GNUC_PRINTF (4, 5);
# define _dbus_verbose(fmt,...) _dbus_verbose_real( __FILE__,__LINE__,__FUNCTION__,fmt, ## __VA_ARGS__)
#else
+DBUS_PRIVATE_EXPORT
void _dbus_verbose_real (const char *format,
...) _DBUS_GNUC_PRINTF (1, 2);
# define _dbus_verbose _dbus_verbose_real
#endif
+DBUS_PRIVATE_EXPORT
void _dbus_verbose_reset_real (void);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_is_verbose_real (void);
+DBUS_PRIVATE_EXPORT
+dbus_bool_t _dbus_get_verbose (void);
+DBUS_PRIVATE_EXPORT
+void _dbus_set_verbose (dbus_bool_t state);
# define _dbus_verbose_reset _dbus_verbose_reset_real
# define _dbus_is_verbose _dbus_is_verbose_real
@@ -122,11 +132,13 @@ void _dbus_trace_ref (const char *obj_name,
const char *env_var,
int *enabled);
+DBUS_PRIVATE_EXPORT
const char* _dbus_strerror (int error_number);
#ifdef DBUS_DISABLE_ASSERT
#define _dbus_assert(condition) do { } while (0)
#else
+DBUS_PRIVATE_EXPORT
void _dbus_real_assert (dbus_bool_t condition,
const char *condition_text,
const char *file,
@@ -139,6 +151,7 @@ void _dbus_real_assert (dbus_bool_t condition,
#ifdef DBUS_DISABLE_ASSERT
#define _dbus_assert_not_reached(explanation) do { } while (0)
#else
+DBUS_PRIVATE_EXPORT
void _dbus_real_assert_not_reached (const char *explanation,
const char *file,
int line) _DBUS_GNUC_NORETURN;
@@ -151,6 +164,7 @@ void _dbus_real_assert_not_reached (const char *explanation,
#define _dbus_return_val_if_fail(condition, val)
#else
+DBUS_PRIVATE_EXPORT
extern const char *_dbus_return_if_fail_warning_format;
#define _dbus_return_if_fail(condition) do { \
@@ -188,8 +202,20 @@ extern const char *_dbus_return_if_fail_warning_format;
#define _DBUS_ASSERT_ERROR_IS_SET(error) do { } while (0)
#define _DBUS_ASSERT_ERROR_IS_CLEAR(error) do { } while (0)
#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)))
+static inline void
+_dbus_assert_error_is_set (const DBusError *error)
+{
+ _dbus_assert (error == NULL || dbus_error_is_set (error));
+}
+
+static inline void
+_dbus_assert_error_is_clear (const DBusError *error)
+{
+ _dbus_assert (error == NULL || !dbus_error_is_set (error));
+}
+
+#define _DBUS_ASSERT_ERROR_IS_SET(error) _dbus_assert_error_is_set(error)
+#define _DBUS_ASSERT_ERROR_IS_CLEAR(error) _dbus_assert_error_is_clear(error)
#endif
#define _dbus_return_if_error_is_set(error) _dbus_return_if_fail ((error) == NULL || !dbus_error_is_set ((error)))
@@ -213,9 +239,11 @@ extern const char *_dbus_return_if_fail_warning_format;
((void*)_DBUS_ALIGN_VALUE(this, boundary))
+DBUS_PRIVATE_EXPORT
char* _dbus_strdup (const char *str);
void* _dbus_memdup (const void *mem,
size_t n_bytes);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_array_contains (const char **array,
const char *str);
char** _dbus_dup_string_array (const char **array);
@@ -251,18 +279,22 @@ char** _dbus_dup_string_array (const char **array);
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);
+DBUS_PRIVATE_EXPORT
void _dbus_verbose_bytes_of_string (const DBusString *str,
int start,
int len);
+DBUS_PRIVATE_EXPORT
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)
+DBUS_PRIVATE_EXPORT
+void _dbus_set_error_valist (DBusError *error,
+ const char *name,
+ const char *format,
+ va_list args) _DBUS_GNUC_PRINTF (3, 0);
#ifdef DBUS_ENABLE_EMBEDDED_TESTS
/* Memory debugging */
@@ -272,9 +304,11 @@ 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);
+DBUS_PRIVATE_EXPORT
int _dbus_get_malloc_blocks_outstanding (void);
typedef dbus_bool_t (* DBusTestMemoryFunction) (void *data);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_test_oom_handling (const char *description,
DBusTestMemoryFunction func,
void *data);
@@ -291,6 +325,7 @@ dbus_bool_t _dbus_test_oom_handling (const char *description,
#endif /* !DBUS_ENABLE_EMBEDDED_TESTS */
typedef void (* DBusShutdownFunction) (void *data);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_register_shutdown_func (DBusShutdownFunction function,
void *data);
dbus_bool_t _dbus_register_shutdown_func_unlocked (DBusShutdownFunction function,
@@ -329,6 +364,7 @@ void _dbus_unlock (DBusGlobalLock lock);
#define _DBUS_LOCK(name) _dbus_lock (_DBUS_LOCK_##name)
#define _DBUS_UNLOCK(name) _dbus_unlock (_DBUS_LOCK_##name)
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_threads_init_debug (void);
dbus_bool_t _dbus_address_append_escaped (DBusString *escaped,
@@ -353,7 +389,10 @@ union DBusGUID
char as_bytes[DBUS_UUID_LENGTH_BYTES]; /**< guid as 16 single-byte values */
};
-void _dbus_generate_uuid (DBusGUID *uuid);
+DBUS_PRIVATE_EXPORT _DBUS_GNUC_WARN_UNUSED_RESULT
+dbus_bool_t _dbus_generate_uuid (DBusGUID *uuid,
+ DBusError *error);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_uuid_encode (const DBusGUID *uuid,
DBusString *encoded);
dbus_bool_t _dbus_read_uuid_file (const DBusString *filename,
@@ -365,7 +404,8 @@ dbus_bool_t _dbus_write_uuid_file (const DBusString *filename,
const DBusGUID *uuid,
DBusError *error);
-dbus_bool_t _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str);
+dbus_bool_t _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str,
+ DBusError *error);
#define _DBUS_PASTE2(a, b) a ## b
#define _DBUS_PASTE(a, b) _DBUS_PASTE2 (a, b)
diff --git a/dbus/dbus-keyring.c b/dbus/dbus-keyring.c
index f0c64de3..bb7e4f8d 100644
--- a/dbus/dbus-keyring.c
+++ b/dbus/dbus-keyring.c
@@ -304,11 +304,8 @@ add_new_key (DBusKey **keys_p,
/* 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;
- }
+ if (!_dbus_generate_random_bytes (&bytes, 4, error))
+ goto out;
s = (const unsigned char*) _dbus_string_get_const_data (&bytes);
@@ -329,9 +326,8 @@ add_new_key (DBusKey **keys_p,
#define KEY_LENGTH_BYTES 24
_dbus_string_set_length (&bytes, 0);
- if (!_dbus_generate_random_bytes (&bytes, KEY_LENGTH_BYTES))
+ if (!_dbus_generate_random_bytes (&bytes, KEY_LENGTH_BYTES, error))
{
- dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto out;
}
diff --git a/dbus/dbus-list.h b/dbus/dbus-list.h
index 910d7383..9350a0da 100644
--- a/dbus/dbus-list.h
+++ b/dbus/dbus-list.h
@@ -37,52 +37,78 @@ struct DBusList
DBusList *next; /**< Next list node. */
void *data; /**< Data stored at this element. */
};
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_list_append (DBusList **list,
void *data);
+DBUS_PRIVATE_EXPORT
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_PRIVATE_EXPORT
dbus_bool_t _dbus_list_insert_after (DBusList **list,
DBusList *after_this_link,
void *data);
+DBUS_PRIVATE_EXPORT
void _dbus_list_insert_before_link (DBusList **list,
DBusList *before_this_link,
DBusList *link);
+DBUS_PRIVATE_EXPORT
void _dbus_list_insert_after_link (DBusList **list,
DBusList *after_this_link,
DBusList *link);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_list_remove (DBusList **list,
void *data);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_list_remove_last (DBusList **list,
void *data);
+DBUS_PRIVATE_EXPORT
void _dbus_list_remove_link (DBusList **list,
DBusList *link);
+DBUS_PRIVATE_EXPORT
DBusList* _dbus_list_find_last (DBusList **list,
void *data);
+DBUS_PRIVATE_EXPORT
void _dbus_list_clear (DBusList **list);
+DBUS_PRIVATE_EXPORT
DBusList* _dbus_list_get_first_link (DBusList **list);
+DBUS_PRIVATE_EXPORT
DBusList* _dbus_list_get_last_link (DBusList **list);
+DBUS_PRIVATE_EXPORT
void* _dbus_list_get_last (DBusList **list);
+DBUS_PRIVATE_EXPORT
void* _dbus_list_get_first (DBusList **list);
+DBUS_PRIVATE_EXPORT
void* _dbus_list_pop_first (DBusList **list);
+DBUS_PRIVATE_EXPORT
void* _dbus_list_pop_last (DBusList **list);
+DBUS_PRIVATE_EXPORT
DBusList* _dbus_list_pop_first_link (DBusList **list);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_list_copy (DBusList **list,
DBusList **dest);
+DBUS_PRIVATE_EXPORT
int _dbus_list_get_length (DBusList **list);
+DBUS_PRIVATE_EXPORT
DBusList* _dbus_list_alloc_link (void *data);
+DBUS_PRIVATE_EXPORT
void _dbus_list_free_link (DBusList *link);
+DBUS_PRIVATE_EXPORT
void _dbus_list_unlink (DBusList **list,
DBusList *link);
+DBUS_PRIVATE_EXPORT
void _dbus_list_append_link (DBusList **list,
DBusList *link);
+DBUS_PRIVATE_EXPORT
void _dbus_list_prepend_link (DBusList **list,
DBusList *link);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_list_length_is_one (DBusList **list);
+DBUS_PRIVATE_EXPORT
void _dbus_list_foreach (DBusList **list,
DBusForeachFunction function,
void *data);
@@ -91,6 +117,7 @@ void _dbus_list_foreach (DBusList **list,
#define _dbus_list_get_prev_link(list, link) ((link) == *(list) ? NULL : (link)->prev)
/* if DBUS_ENABLE_STATS */
+DBUS_PRIVATE_EXPORT
void _dbus_list_get_stats (dbus_uint32_t *in_use_p,
dbus_uint32_t *in_free_list_p,
dbus_uint32_t *allocated_p);
diff --git a/dbus/dbus-macros.h b/dbus/dbus-macros.h
index 8d6c3000..a82d911e 100644
--- a/dbus/dbus-macros.h
+++ b/dbus/dbus-macros.h
@@ -182,7 +182,9 @@
* platforms other than Windows.
*/
-#if defined(_WIN32)
+#if defined(DBUS_EXPORT)
+ /* value forced by compiler command line, don't redefine */
+#elif defined(_WIN32)
# if defined(DBUS_STATIC_BUILD)
# define DBUS_EXPORT
# elif defined(dbus_1_EXPORTS)
@@ -190,10 +192,28 @@
# else
# define DBUS_EXPORT __declspec(dllimport)
# endif
+#elif defined(__GNUC__) && __GNUC__ >= 4
+# define DBUS_EXPORT __attribute__ ((__visibility__ ("default")))
#else
#define DBUS_EXPORT
#endif
+#if defined(DBUS_PRIVATE_EXPORT)
+ /* value forced by compiler command line, don't redefine */
+#elif defined(_WIN32)
+# if defined(DBUS_STATIC_BUILD)
+# define DBUS_PRIVATE_EXPORT /* no decoration */
+# elif defined(dbus_1_EXPORTS)
+# define DBUS_PRIVATE_EXPORT __declspec(dllexport)
+# else
+# define DBUS_PRIVATE_EXPORT __declspec(dllimport)
+# endif
+#elif defined(__GNUC__) && __GNUC__ >= 4
+# define DBUS_PRIVATE_EXPORT __attribute__ ((__visibility__ ("default")))
+#else
+# define DBUS_PRIVATE_EXPORT /* no decoration */
+#endif
+
/** @} */
#endif /* DBUS_MACROS_H */
diff --git a/dbus/dbus-mainloop.c b/dbus/dbus-mainloop.c
index 7ff9dc2c..f6736fe1 100644
--- a/dbus/dbus-mainloop.c
+++ b/dbus/dbus-mainloop.c
@@ -37,7 +37,7 @@
struct DBusLoop
{
int refcount;
- /** fd => dbus_malloc'd DBusList ** of references to DBusWatch */
+ /** DBusPollable => dbus_malloc'd DBusList ** of references to DBusWatch */
DBusHashTable *watches;
DBusSocketSet *socket_set;
DBusList *timeouts;
@@ -54,8 +54,8 @@ struct DBusLoop
typedef struct
{
DBusTimeout *timeout;
- unsigned long last_tv_sec;
- unsigned long last_tv_usec;
+ long last_tv_sec;
+ long last_tv_usec;
} TimeoutCallback;
#define TIMEOUT_CALLBACK(callback) ((TimeoutCallback*)callback)
@@ -112,7 +112,7 @@ _dbus_loop_new (void)
if (loop == NULL)
return NULL;
- loop->watches = _dbus_hash_table_new (DBUS_HASH_INT, NULL,
+ loop->watches = _dbus_hash_table_new (DBUS_HASH_POLLABLE, NULL,
free_watch_table_entry);
loop->socket_set = _dbus_socket_set_new (0);
@@ -168,12 +168,12 @@ _dbus_loop_unref (DBusLoop *loop)
}
static DBusList **
-ensure_watch_table_entry (DBusLoop *loop,
- int fd)
+ensure_watch_table_entry (DBusLoop *loop,
+ DBusPollable fd)
{
DBusList **watches;
- watches = _dbus_hash_table_lookup_int (loop->watches, fd);
+ watches = _dbus_hash_table_lookup_pollable (loop->watches, fd);
if (watches == NULL)
{
@@ -182,7 +182,7 @@ ensure_watch_table_entry (DBusLoop *loop,
if (watches == NULL)
return watches;
- if (!_dbus_hash_table_insert_int (loop->watches, fd, watches))
+ if (!_dbus_hash_table_insert_pollable (loop->watches, fd, watches))
{
dbus_free (watches);
watches = NULL;
@@ -193,14 +193,15 @@ ensure_watch_table_entry (DBusLoop *loop,
}
static void
-cull_watches_for_invalid_fd (DBusLoop *loop,
- int fd)
+cull_watches_for_invalid_fd (DBusLoop *loop,
+ DBusPollable fd)
{
DBusList *link;
DBusList **watches;
- _dbus_warn ("invalid request, socket fd %d not open\n", fd);
- watches = _dbus_hash_table_lookup_int (loop->watches, fd);
+ _dbus_warn ("invalid request, socket fd %" DBUS_POLLABLE_FORMAT " not open\n",
+ _dbus_pollable_printable (fd));
+ watches = _dbus_hash_table_lookup_pollable (loop->watches, fd);
if (watches != NULL)
{
@@ -210,13 +211,13 @@ cull_watches_for_invalid_fd (DBusLoop *loop,
_dbus_watch_invalidate (link->data);
}
- _dbus_hash_table_remove_int (loop->watches, fd);
+ _dbus_hash_table_remove_pollable (loop->watches, fd);
}
static dbus_bool_t
-gc_watch_table_entry (DBusLoop *loop,
- DBusList **watches,
- int fd)
+gc_watch_table_entry (DBusLoop *loop,
+ DBusList **watches,
+ DBusPollable fd)
{
/* If watches is already NULL we have nothing to do */
if (watches == NULL)
@@ -226,23 +227,23 @@ gc_watch_table_entry (DBusLoop *loop,
if (*watches != NULL)
return FALSE;
- _dbus_hash_table_remove_int (loop->watches, fd);
+ _dbus_hash_table_remove_pollable (loop->watches, fd);
return TRUE;
}
static void
-refresh_watches_for_fd (DBusLoop *loop,
- DBusList **watches,
- int fd)
+refresh_watches_for_fd (DBusLoop *loop,
+ DBusList **watches,
+ DBusPollable fd)
{
DBusList *link;
unsigned int flags = 0;
dbus_bool_t interested = FALSE;
- _dbus_assert (fd != -1);
+ _dbus_assert (_dbus_pollable_is_valid (fd));
if (watches == NULL)
- watches = _dbus_hash_table_lookup_int (loop->watches, fd);
+ watches = _dbus_hash_table_lookup_pollable (loop->watches, fd);
/* we allocated this in the first _dbus_loop_add_watch for the fd, and keep
* it until there are none left */
@@ -270,11 +271,11 @@ dbus_bool_t
_dbus_loop_add_watch (DBusLoop *loop,
DBusWatch *watch)
{
- int fd;
+ DBusPollable fd;
DBusList **watches;
- fd = dbus_watch_get_socket (watch);
- _dbus_assert (fd != -1);
+ fd = _dbus_watch_get_pollable (watch);
+ _dbus_assert (_dbus_pollable_is_valid (fd));
watches = ensure_watch_table_entry (loop, fd);
@@ -295,7 +296,7 @@ _dbus_loop_add_watch (DBusLoop *loop,
dbus_watch_get_flags (watch),
dbus_watch_get_enabled (watch)))
{
- _dbus_hash_table_remove_int (loop->watches, fd);
+ _dbus_hash_table_remove_pollable (loop->watches, fd);
return FALSE;
}
}
@@ -314,7 +315,7 @@ void
_dbus_loop_toggle_watch (DBusLoop *loop,
DBusWatch *watch)
{
- refresh_watches_for_fd (loop, NULL, dbus_watch_get_socket (watch));
+ refresh_watches_for_fd (loop, NULL, _dbus_watch_get_pollable (watch));
}
void
@@ -323,15 +324,15 @@ _dbus_loop_remove_watch (DBusLoop *loop,
{
DBusList **watches;
DBusList *link;
- int fd;
+ DBusPollable fd;
/* This relies on people removing watches before they invalidate them,
* which has been safe since fd.o #33336 was fixed. Assert about it
* so we don't regress. */
- fd = dbus_watch_get_socket (watch);
- _dbus_assert (fd != -1);
+ fd = _dbus_watch_get_pollable (watch);
+ _dbus_assert (_dbus_pollable_is_valid (fd));
- watches = _dbus_hash_table_lookup_int (loop->watches, fd);
+ watches = _dbus_hash_table_lookup_pollable (loop->watches, fd);
if (watches != NULL)
{
@@ -421,15 +422,15 @@ _dbus_loop_remove_timeout (DBusLoop *loop,
* to do this.
*/
static dbus_bool_t
-check_timeout (unsigned long tv_sec,
- unsigned long tv_usec,
+check_timeout (long tv_sec,
+ long tv_usec,
TimeoutCallback *tcb,
int *timeout)
{
long sec_remaining;
long msec_remaining;
- unsigned long expiration_tv_sec;
- unsigned long expiration_tv_usec;
+ long expiration_tv_sec;
+ long expiration_tv_usec;
long interval_seconds;
long interval_milliseconds;
int interval;
@@ -450,10 +451,7 @@ check_timeout (unsigned long tv_sec,
}
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;
+ msec_remaining = (expiration_tv_usec - tv_usec) / 1000L;
#if MAINLOOP_SPEW
_dbus_verbose ("Interval is %ld seconds %ld msecs\n",
@@ -595,8 +593,8 @@ _dbus_loop_iterate (DBusLoop *loop,
timeout = -1;
if (loop->timeout_count > 0)
{
- unsigned long tv_sec;
- unsigned long tv_usec;
+ long tv_sec;
+ long tv_usec;
_dbus_get_monotonic_time (&tv_sec, &tv_usec);
@@ -672,11 +670,11 @@ _dbus_loop_iterate (DBusLoop *loop,
while (_dbus_hash_iter_next (&hash_iter))
{
DBusList **watches;
- int fd;
+ DBusPollable fd;
dbus_bool_t changed;
changed = FALSE;
- fd = _dbus_hash_iter_get_int_key (&hash_iter);
+ fd = _dbus_hash_iter_get_pollable_key (&hash_iter);
watches = _dbus_hash_iter_get_value (&hash_iter);
for (link = _dbus_list_get_first_link (watches);
@@ -704,8 +702,8 @@ _dbus_loop_iterate (DBusLoop *loop,
if (loop->timeout_count > 0)
{
- unsigned long tv_sec;
- unsigned long tv_usec;
+ long tv_sec;
+ long tv_usec;
_dbus_get_monotonic_time (&tv_sec, &tv_usec);
@@ -798,8 +796,8 @@ _dbus_loop_iterate (DBusLoop *loop,
if (condition == 0)
continue;
- watches = _dbus_hash_table_lookup_int (loop->watches,
- ready_fds[i].fd);
+ watches = _dbus_hash_table_lookup_pollable (loop->watches,
+ ready_fds[i].fd);
if (watches == NULL)
continue;
diff --git a/dbus/dbus-marshal-basic.c b/dbus/dbus-marshal-basic.c
index eafc2a9a..74fe3f91 100644
--- a/dbus/dbus-marshal-basic.c
+++ b/dbus/dbus-marshal-basic.c
@@ -599,7 +599,7 @@ marshal_2_octets (DBusString *str,
dbus_bool_t retval;
int orig_len;
- _dbus_assert (sizeof (value) == 2);
+ _DBUS_STATIC_ASSERT (sizeof (value) == 2);
if (byte_order != DBUS_COMPILER_BYTE_ORDER)
value = DBUS_UINT16_SWAP_LE_BE (value);
@@ -628,7 +628,7 @@ marshal_4_octets (DBusString *str,
dbus_bool_t retval;
int orig_len;
- _dbus_assert (sizeof (value) == 4);
+ _DBUS_STATIC_ASSERT (sizeof (value) == 4);
if (byte_order != DBUS_COMPILER_BYTE_ORDER)
value = DBUS_UINT32_SWAP_LE_BE (value);
@@ -657,7 +657,7 @@ marshal_8_octets (DBusString *str,
dbus_bool_t retval;
int orig_len;
- _dbus_assert (sizeof (value) == 8);
+ _DBUS_STATIC_ASSERT (sizeof (value) == 8);
swap_8_octets (&value, byte_order);
@@ -1580,7 +1580,7 @@ swap_test_array (void *array,
#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)) \
+ if (memcmp (literal, v_ARRAY_##typename, sizeof (literal)) != 0) \
{ \
_dbus_verbose ("MARSHALED DATA\n"); \
_dbus_verbose_bytes_of_string (&str, dump_pos, \
diff --git a/dbus/dbus-marshal-basic.h b/dbus/dbus-marshal-basic.h
index 9df67cb8..68ff348b 100644
--- a/dbus/dbus-marshal-basic.h
+++ b/dbus/dbus-marshal-basic.h
@@ -148,6 +148,7 @@
#endif
#ifndef _dbus_unpack_uint16
+DBUS_PRIVATE_EXPORT
dbus_uint16_t _dbus_unpack_uint16 (int byte_order,
const unsigned char *data);
#endif
@@ -156,6 +157,7 @@ void _dbus_pack_uint32 (dbus_uint32_t value,
int byte_order,
unsigned char *data);
#ifndef _dbus_unpack_uint32
+DBUS_PRIVATE_EXPORT
dbus_uint32_t _dbus_unpack_uint32 (int byte_order,
const unsigned char *data);
#endif
@@ -201,18 +203,22 @@ void _dbus_marshal_skip_array (const DBusString *str,
int element_type,
int byte_order,
int *pos);
+DBUS_PRIVATE_EXPORT
void _dbus_marshal_set_uint32 (DBusString *str,
int pos,
dbus_uint32_t value,
int byte_order);
+DBUS_PRIVATE_EXPORT
dbus_uint32_t _dbus_marshal_read_uint32 (const DBusString *str,
int pos,
int byte_order,
int *new_pos);
int _dbus_type_get_alignment (int typecode);
int _dbus_type_get_alignment (int typecode);
+DBUS_PRIVATE_EXPORT
const char* _dbus_type_to_string (int typecode);
+DBUS_PRIVATE_EXPORT
int _dbus_first_type_in_signature (const DBusString *str,
int pos);
diff --git a/dbus/dbus-marshal-byteswap.h b/dbus/dbus-marshal-byteswap.h
index be2dd758..f66f2e21 100644
--- a/dbus/dbus-marshal-byteswap.h
+++ b/dbus/dbus-marshal-byteswap.h
@@ -27,6 +27,7 @@
#include <dbus/dbus-protocol.h>
#include <dbus/dbus-marshal-recursive.h>
+DBUS_PRIVATE_EXPORT
void _dbus_marshal_byteswap (const DBusString *signature,
int signature_start,
int old_byte_order,
diff --git a/dbus/dbus-marshal-header.h b/dbus/dbus-marshal-header.h
index 350fe5c4..c8c01129 100644
--- a/dbus/dbus-marshal-header.h
+++ b/dbus/dbus-marshal-header.h
@@ -78,6 +78,7 @@ void _dbus_header_set_serial (DBusHeader *header,
dbus_uint32_t _dbus_header_get_serial (DBusHeader *header);
void _dbus_header_update_lengths (DBusHeader *header,
int body_len);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_header_set_field_basic (DBusHeader *header,
int field,
int type,
@@ -86,10 +87,12 @@ dbus_bool_t _dbus_header_get_field_basic (DBusHeader *header,
int field,
int type,
void *value);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_header_get_field_raw (DBusHeader *header,
int field,
const DBusString **str,
int *pos);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_header_delete_field (DBusHeader *header,
int field);
void _dbus_header_toggle_flag (DBusHeader *header,
@@ -121,6 +124,7 @@ dbus_bool_t _dbus_header_load (DBusHeader *header,
int len);
void _dbus_header_byteswap (DBusHeader *header,
int new_order);
+DBUS_PRIVATE_EXPORT
char _dbus_header_get_byte_order (const DBusHeader *header);
diff --git a/dbus/dbus-marshal-recursive-util.c b/dbus/dbus-marshal-recursive-util.c
index 0e2b4201..3bc26a8c 100644
--- a/dbus/dbus-marshal-recursive-util.c
+++ b/dbus/dbus-marshal-recursive-util.c
@@ -2774,7 +2774,7 @@ signature_from_seed (char *buf,
{
/* try to avoid ascending, descending, or alternating length to help find bugs */
const char *sample_signatures[] = {
- "asax"
+ "asax",
"",
"asau(xxxx)",
"x",
diff --git a/dbus/dbus-marshal-recursive.h b/dbus/dbus-marshal-recursive.h
index acbfd731..fa1d1efa 100644
--- a/dbus/dbus-marshal-recursive.h
+++ b/dbus/dbus-marshal-recursive.h
@@ -96,37 +96,48 @@ struct DBusArrayLenFixup
int new_len; /**< the new value of the length in the written-out block */
};
+DBUS_PRIVATE_EXPORT
void _dbus_type_reader_init (DBusTypeReader *reader,
int byte_order,
const DBusString *type_str,
int type_pos,
const DBusString *value_str,
int value_pos);
+DBUS_PRIVATE_EXPORT
void _dbus_type_reader_init_types_only (DBusTypeReader *reader,
const DBusString *type_str,
int type_pos);
+DBUS_PRIVATE_EXPORT
int _dbus_type_reader_get_current_type (const DBusTypeReader *reader);
+DBUS_PRIVATE_EXPORT
int _dbus_type_reader_get_element_type (const DBusTypeReader *reader);
int _dbus_type_reader_get_value_pos (const DBusTypeReader *reader);
+DBUS_PRIVATE_EXPORT
void _dbus_type_reader_read_basic (const DBusTypeReader *reader,
void *value);
int _dbus_type_reader_get_array_length (const DBusTypeReader *reader);
+DBUS_PRIVATE_EXPORT
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);
+DBUS_PRIVATE_EXPORT
void _dbus_type_reader_recurse (DBusTypeReader *reader,
DBusTypeReader *subreader);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_type_reader_next (DBusTypeReader *reader);
dbus_bool_t _dbus_type_reader_has_next (const DBusTypeReader *reader);
+DBUS_PRIVATE_EXPORT
void _dbus_type_reader_get_signature (const DBusTypeReader *reader,
const DBusString **str_p,
int *start_p,
int *len_p);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_type_reader_set_basic (DBusTypeReader *reader,
const void *value,
const DBusTypeReader *realign_root);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_type_reader_delete (DBusTypeReader *reader,
const DBusTypeReader *realign_root);
@@ -136,6 +147,7 @@ dbus_bool_t _dbus_type_reader_equal_values (const DBusTypeReader *l
void _dbus_type_signature_next (const char *signature,
int *type_pos);
+DBUS_PRIVATE_EXPORT
void _dbus_type_writer_init (DBusTypeWriter *writer,
int byte_order,
DBusString *type_str,
@@ -150,30 +162,36 @@ void _dbus_type_writer_add_types (DBusTypeWriter *write
DBusString *type_str,
int type_pos);
void _dbus_type_writer_remove_types (DBusTypeWriter *writer);
+DBUS_PRIVATE_EXPORT
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_PRIVATE_EXPORT
dbus_bool_t _dbus_type_writer_write_basic (DBusTypeWriter *writer,
int type,
const void *value);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_type_writer_write_fixed_multi (DBusTypeWriter *writer,
int element_type,
const void *value,
int n_elements);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_type_writer_recurse (DBusTypeWriter *writer,
int container_type,
const DBusString *contained_type,
int contained_type_start,
DBusTypeWriter *sub);
+DBUS_PRIVATE_EXPORT
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_PRIVATE_EXPORT
dbus_bool_t _dbus_type_writer_write_reader (DBusTypeWriter *writer,
DBusTypeReader *reader);
diff --git a/dbus/dbus-marshal-validate-util.c b/dbus/dbus-marshal-validate-util.c
index d52cb6d8..2880a4d9 100644
--- a/dbus/dbus-marshal-validate-util.c
+++ b/dbus/dbus-marshal-validate-util.c
@@ -118,7 +118,7 @@ _dbus_marshal_validate_test (void)
"bar",
"bar/baz",
"/foo/bar/",
- "/foo/"
+ "/foo/",
"foo/",
"boo//blah",
"//",
diff --git a/dbus/dbus-marshal-validate.h b/dbus/dbus-marshal-validate.h
index 06434201..8ab024fe 100644
--- a/dbus/dbus-marshal-validate.h
+++ b/dbus/dbus-marshal-validate.h
@@ -116,9 +116,11 @@ typedef enum
DBUS_VALIDITY_LAST
} DBusValidity;
+DBUS_PRIVATE_EXPORT
DBusValidity _dbus_validate_signature_with_reason (const DBusString *type_str,
int type_pos,
int len);
+DBUS_PRIVATE_EXPORT
DBusValidity _dbus_validate_body_with_reason (const DBusString *expected_signature,
int expected_signature_start,
int byte_order,
@@ -129,24 +131,31 @@ DBusValidity _dbus_validate_body_with_reason (const DBusString *expected_si
const char *_dbus_validity_to_error_message (DBusValidity validity);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_validate_path (const DBusString *str,
int start,
int len);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_validate_interface (const DBusString *str,
int start,
int len);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_validate_member (const DBusString *str,
int start,
int len);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_validate_error_name (const DBusString *str,
int start,
int len);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_validate_bus_name (const DBusString *str,
int start,
int len);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_validate_bus_namespace (const DBusString *str,
int start,
int len);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_validate_signature (const DBusString *str,
int start,
int len);
diff --git a/dbus/dbus-memory.c b/dbus/dbus-memory.c
index 22e80727..67d5cb05 100644
--- a/dbus/dbus-memory.c
+++ b/dbus/dbus-memory.c
@@ -862,6 +862,13 @@ _dbus_register_shutdown_func_unlocked (DBusShutdownFunction func,
* You MUST free all memory and release all reference counts
* returned to you by libdbus prior to calling dbus_shutdown().
*
+ * If a shared connection is open, calling dbus_shutdown() will
+ * drain its queue of messages and disconnect it. In particular,
+ * this will result in processing of the special Disconnected
+ * signal, which may result in a call to _exit(), unless you
+ * have used dbus_connection_set_exit_on_disconnect() to disable
+ * that behaviour.
+ *
* 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,
diff --git a/dbus/dbus-mempool.h b/dbus/dbus-mempool.h
index 6693eeb2..bc465ac4 100644
--- a/dbus/dbus-mempool.h
+++ b/dbus/dbus-mempool.h
@@ -32,10 +32,14 @@ DBUS_BEGIN_DECLS
typedef struct DBusMemPool DBusMemPool;
+DBUS_PRIVATE_EXPORT
DBusMemPool* _dbus_mem_pool_new (int element_size,
dbus_bool_t zero_elements);
+DBUS_PRIVATE_EXPORT
void _dbus_mem_pool_free (DBusMemPool *pool);
+DBUS_PRIVATE_EXPORT
void* _dbus_mem_pool_alloc (DBusMemPool *pool);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_mem_pool_dealloc (DBusMemPool *pool,
void *element);
diff --git a/dbus/dbus-message-internal.h b/dbus/dbus-message-internal.h
index e9a9ec01..4bb4d8bc 100644
--- a/dbus/dbus-message-internal.h
+++ b/dbus/dbus-message-internal.h
@@ -50,6 +50,7 @@ typedef struct DBusMessageLoader DBusMessageLoader;
void _dbus_message_get_network_data (DBusMessage *message,
const DBusString **header,
const DBusString **body);
+DBUS_PRIVATE_EXPORT
void _dbus_message_get_unix_fds (DBusMessage *message,
const int **fds,
unsigned *n_fds);
@@ -63,34 +64,45 @@ void _dbus_message_add_counter_link (DBusMessage *message,
void _dbus_message_remove_counter (DBusMessage *message,
DBusCounter *counter);
+DBUS_PRIVATE_EXPORT
DBusMessageLoader* _dbus_message_loader_new (void);
+DBUS_PRIVATE_EXPORT
DBusMessageLoader* _dbus_message_loader_ref (DBusMessageLoader *loader);
+DBUS_PRIVATE_EXPORT
void _dbus_message_loader_unref (DBusMessageLoader *loader);
+DBUS_PRIVATE_EXPORT
void _dbus_message_loader_get_buffer (DBusMessageLoader *loader,
DBusString **buffer);
+DBUS_PRIVATE_EXPORT
void _dbus_message_loader_return_buffer (DBusMessageLoader *loader,
DBusString *buffer);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_message_loader_get_unix_fds (DBusMessageLoader *loader,
int **fds,
unsigned *max_n_fds);
+DBUS_PRIVATE_EXPORT
void _dbus_message_loader_return_unix_fds (DBusMessageLoader *loader,
int *fds,
unsigned n_fds);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_message_loader_queue_messages (DBusMessageLoader *loader);
DBusMessage* _dbus_message_loader_peek_message (DBusMessageLoader *loader);
+DBUS_PRIVATE_EXPORT
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_PRIVATE_EXPORT
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);
+DBUS_PRIVATE_EXPORT
long _dbus_message_loader_get_max_message_size (DBusMessageLoader *loader);
void _dbus_message_loader_set_max_message_unix_fds(DBusMessageLoader *loader,
diff --git a/dbus/dbus-message-private.h b/dbus/dbus-message-private.h
index a611b095..50c41a8f 100644
--- a/dbus/dbus-message-private.h
+++ b/dbus/dbus-message-private.h
@@ -133,6 +133,7 @@ struct DBusMessage
#endif
};
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
DBusError *error,
int first_arg_type,
diff --git a/dbus/dbus-message-util.c b/dbus/dbus-message-util.c
index f615af83..5acd541e 100644
--- a/dbus/dbus-message-util.c
+++ b/dbus/dbus-message-util.c
@@ -1045,8 +1045,10 @@ verify_test_message_memleak (DBusMessage *message)
int our_string_array_len1;
char **our_string_array2;
int our_string_array_len2;
+#ifdef HAVE_UNIX_FD_PASSING
int our_unix_fd1;
int our_unix_fd2;
+#endif
DBusInitialFDs *initial_fds;
initial_fds = _dbus_check_fdleaks_enter ();
@@ -1205,6 +1207,17 @@ _dbus_message_test (const char *test_data_dir)
#endif
char **decomposed;
DBusInitialFDs *initial_fds;
+ dbus_bool_t ok;
+ char basic_types[] = DBUS_TYPE_BYTE_AS_STRING \
+ DBUS_TYPE_BOOLEAN_AS_STRING \
+ DBUS_TYPE_INT16_AS_STRING \
+ DBUS_TYPE_INT32_AS_STRING \
+ DBUS_TYPE_INT64_AS_STRING \
+ DBUS_TYPE_UINT16_AS_STRING \
+ DBUS_TYPE_UINT32_AS_STRING \
+ DBUS_TYPE_UINT64_AS_STRING \
+ DBUS_TYPE_DOUBLE_AS_STRING \
+ DBUS_TYPE_STRING_AS_STRING;
initial_fds = _dbus_check_fdleaks_enter ();
@@ -1595,6 +1608,56 @@ _dbus_message_test (const char *test_data_dir)
_dbus_check_fdleaks_leave (initial_fds);
initial_fds = _dbus_check_fdleaks_enter ();
+ /* Test enumeration of array elements */
+ for (i = strlen (basic_types) - 1; i > 0; i--)
+ {
+ DBusBasicValue val;
+ int some;
+ char* signature = _dbus_strdup ("?");
+
+ signature[0] = basic_types[i];
+ s = "SomeThingToSay";
+ memset (&val, '\0', sizeof (val));
+
+ message = dbus_message_new_method_call ("de.ende.test",
+ "/de/ende/test", "de.ende.Test", "ArtistName");
+ _dbus_assert (message != NULL);
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY,
+ signature, &array_iter);
+ for (some = 0; some < 3; some++)
+ {
+ if (basic_types[i] == DBUS_TYPE_STRING)
+ dbus_message_iter_append_basic (&array_iter, DBUS_TYPE_STRING, &s);
+ else
+ dbus_message_iter_append_basic (&array_iter, basic_types[i], &val);
+ }
+ dbus_message_iter_close_container (&iter, &array_iter);
+ dbus_message_iter_init (message, &iter);
+ _dbus_assert (dbus_message_iter_get_element_count (&iter) == some);
+ dbus_message_unref (message);
+ dbus_free (signature);
+ }
+ /* Array of structs */
+ message = dbus_message_new_method_call ("de.ende.test",
+ "/de/ende/test", "de.ende.Test", "ArtistName");
+ _dbus_assert (message != NULL);
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY,
+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_STRUCT_END_CHAR_AS_STRING, &array_iter);
+ dbus_message_iter_open_container (&array_iter, DBUS_TYPE_STRUCT,
+ NULL, &struct_iter);
+ s = "SpamAndEggs";
+ dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &s);
+ dbus_message_iter_close_container (&array_iter, &struct_iter);
+ dbus_message_iter_close_container (&iter, &array_iter);
+ dbus_message_iter_init (message, &iter);
+ _dbus_assert (dbus_message_iter_get_element_count (&iter) == 1);
+ dbus_message_unref (message);
+ check_memleaks ();
+
/* Check that we can abandon a container */
message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
"/org/freedesktop/TestPath",
@@ -1603,18 +1666,19 @@ _dbus_message_test (const char *test_data_dir)
dbus_message_iter_init_append (message, &iter);
- _dbus_assert (dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY,
+ ok = 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));
-
+ &array_iter);
+ _dbus_assert (ok);
+ ok = dbus_message_iter_open_container (&array_iter, DBUS_TYPE_STRUCT,
+ NULL, &struct_iter);
+ _dbus_assert (ok);
s = "peaches";
- _dbus_assert (dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING,
- &s));
+ ok = dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &s);
+ _dbus_assert (ok);
/* uh-oh, error, try and unwind */
diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c
index 1f433712..699e022b 100644
--- a/dbus/dbus-message.c
+++ b/dbus/dbus-message.c
@@ -602,7 +602,7 @@ static void
close_unix_fds(int *fds, unsigned *n_fds)
{
DBusError e;
- int i;
+ unsigned int i;
if (*n_fds <= 0)
return;
@@ -2025,7 +2025,7 @@ _dbus_message_iter_init_common (DBusMessage *message,
DBusMessageRealIter *real,
int iter_type)
{
- _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter));
+ _DBUS_STATIC_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
@@ -2325,20 +2325,56 @@ dbus_message_iter_get_basic (DBusMessageIter *iter,
}
/**
+ * Returns the number of elements in the array-typed value pointed
+ * to by the iterator.
+ * Note that this function is O(1) for arrays of fixed-size types
+ * but O(n) for arrays of variable-length types such as strings,
+ * so it may be a bad idea to use it.
+ *
+ * @param iter the iterator
+ * @returns the number of elements in the array
+ */
+int
+dbus_message_iter_get_element_count (DBusMessageIter *iter)
+{
+ DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
+ DBusTypeReader array;
+ int element_type;
+ int n_elements = 0;
+
+ _dbus_return_val_if_fail (_dbus_message_iter_check (real), 0);
+ _dbus_return_val_if_fail (_dbus_type_reader_get_current_type (&real->u.reader)
+ == DBUS_TYPE_ARRAY, 0);
+
+ element_type = _dbus_type_reader_get_element_type (&real->u.reader);
+ _dbus_type_reader_recurse (&real->u.reader, &array);
+ if (dbus_type_is_fixed (element_type))
+ {
+ int alignment = _dbus_type_get_alignment (element_type);
+ int total_len = _dbus_type_reader_get_array_length (&array);
+ n_elements = total_len / alignment;
+ }
+ else
+ {
+ while (_dbus_type_reader_get_current_type (&array) != DBUS_TYPE_INVALID)
+ {
+ ++n_elements;
+ _dbus_type_reader_next (&array);
+ }
+ }
+
+ return n_elements;
+}
+
+/**
* 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.
+ * in the wire protocol? Use dbus_message_iter_get_element_count() instead.
*
- * @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
*/
@@ -4879,6 +4915,54 @@ dbus_message_demarshal_bytes_needed(const char *buf,
}
}
+/**
+ * Sets a flag indicating that the caller of the method is prepared
+ * to wait for interactive authorization to take place (for instance
+ * via Polkit) before the actual method is processed.
+ *
+ * The flag is #FALSE by default; that is, by default the other end is
+ * expected to make any authorization decisions non-interactively
+ * and promptly. It may use the error
+ * #DBUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED to signal that
+ * authorization failed, but could have succeeded if this flag had
+ * been used.
+ *
+ * For messages whose type is not #DBUS_MESSAGE_TYPE_METHOD_CALL,
+ * this flag is meaningless and should not be set.
+ *
+ * On the protocol level this toggles
+ * #DBUS_HEADER_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION.
+ *
+ * @param message the message
+ * @param allow #TRUE if interactive authorization is acceptable
+ */
+void
+dbus_message_set_allow_interactive_authorization (DBusMessage *message,
+ dbus_bool_t allow)
+{
+ _dbus_return_if_fail (message != NULL);
+ _dbus_return_if_fail (!message->locked);
+
+ _dbus_header_toggle_flag (&message->header,
+ DBUS_HEADER_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION,
+ allow);
+}
+
+/**
+ * Returns whether the flag controlled by
+ * dbus_message_set_allow_interactive_authorization() has been set.
+ *
+ * @param message the message
+ */
+dbus_bool_t
+dbus_message_get_allow_interactive_authorization (DBusMessage *message)
+{
+ _dbus_return_val_if_fail (message != NULL, FALSE);
+
+ return _dbus_header_get_flag (&message->header,
+ DBUS_HEADER_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION);
+}
+
/** @} */
/* tests in dbus-message-util.c */
diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h
index 4fd44dab..3e33eb7b 100644
--- a/dbus/dbus-message.h
+++ b/dbus/dbus-message.h
@@ -226,6 +226,9 @@ void dbus_message_iter_recurse (DBusMessageIter *iter,
DBUS_EXPORT
void dbus_message_iter_get_basic (DBusMessageIter *iter,
void *value);
+DBUS_EXPORT
+int dbus_message_iter_get_element_count(DBusMessageIter *iter);
+
#ifndef DBUS_DISABLE_DEPRECATED
/* This function returns the wire protocol size of the array in bytes,
* you do not want to know that probably
@@ -302,6 +305,14 @@ DBUS_EXPORT
int dbus_message_demarshal_bytes_needed (const char *str,
int len);
+DBUS_EXPORT
+void dbus_message_set_allow_interactive_authorization (DBusMessage *message,
+ dbus_bool_t allow);
+
+DBUS_EXPORT
+dbus_bool_t dbus_message_get_allow_interactive_authorization (
+ DBusMessage *message);
+
/** @} */
DBUS_END_DECLS
diff --git a/dbus/dbus-misc.c b/dbus/dbus-misc.c
index 6ca30f24..a2da562a 100644
--- a/dbus/dbus-misc.c
+++ b/dbus/dbus-misc.c
@@ -80,7 +80,11 @@ dbus_get_local_machine_id (void)
if (!_dbus_string_init (&uuid))
return NULL;
- if (!_dbus_get_local_machine_uuid_encoded (&uuid) ||
+ /* The documentation says dbus_get_local_machine_id() only fails on OOM;
+ * this can actually also fail if the D-Bus installation is faulty
+ * (no UUID) *and* reading a new random UUID fails, but we have no way
+ * to report that */
+ if (!_dbus_get_local_machine_uuid_encoded (&uuid, NULL) ||
!_dbus_string_steal_data (&uuid, &s))
{
_dbus_string_free (&uuid);
diff --git a/dbus/dbus-nonce.c b/dbus/dbus-nonce.c
index 0018d171..3c0f6f37 100644
--- a/dbus/dbus-nonce.c
+++ b/dbus/dbus-nonce.c
@@ -31,7 +31,7 @@
#include <stdio.h>
static dbus_bool_t
-do_check_nonce (int fd, const DBusString *nonce, DBusError *error)
+do_check_nonce (DBusSocket fd, const DBusString *nonce, DBusError *error)
{
DBusString buffer;
DBusString p;
@@ -53,10 +53,14 @@ do_check_nonce (int fd, const DBusString *nonce, DBusError *error)
while (nleft)
{
+ int saved_errno;
+
n = _dbus_read_socket (fd, &p, nleft);
- if (n == -1 && _dbus_get_is_errno_eintr())
+ saved_errno = _dbus_save_socket_errno ();
+
+ if (n == -1 && _dbus_get_is_errno_eintr (saved_errno))
;
- else if (n == -1 && _dbus_get_is_errno_eagain_or_ewouldblock())
+ else if (n == -1 && _dbus_get_is_errno_eagain_or_ewouldblock (saved_errno))
_dbus_sleep_milliseconds (100);
else if (n==-1)
{
@@ -144,25 +148,25 @@ _dbus_read_nonce (const DBusString *fname, DBusString *nonce, DBusError* error)
return TRUE;
}
-int
-_dbus_accept_with_noncefile (int listen_fd, const DBusNonceFile *noncefile)
+DBusSocket
+_dbus_accept_with_noncefile (DBusSocket listen_fd, const DBusNonceFile *noncefile)
{
- int fd;
+ DBusSocket fd;
DBusString nonce;
_dbus_assert (noncefile != NULL);
if (!_dbus_string_init (&nonce))
- return -1;
+ return _dbus_socket_get_invalid ();
//PENDING(kdab): set better errors
if (_dbus_read_nonce (_dbus_noncefile_get_path(noncefile), &nonce, NULL) != TRUE)
- return -1;
+ return _dbus_socket_get_invalid ();
fd = _dbus_accept (listen_fd);
- if (_dbus_socket_is_invalid (fd))
+ if (!_dbus_socket_is_valid (fd))
return fd;
if (do_check_nonce(fd, &nonce, NULL) != TRUE) {
_dbus_verbose ("nonce check failed. Closing socket.\n");
_dbus_close_socket(fd, NULL);
- return -1;
+ return _dbus_socket_get_invalid ();
}
return fd;
@@ -182,9 +186,8 @@ generate_and_write_nonce (const DBusString *filename, DBusError *error)
return FALSE;
}
- if (!_dbus_generate_random_bytes (&nonce, 16))
+ if (!_dbus_generate_random_bytes (&nonce, 16, error))
{
- dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
_dbus_string_free (&nonce);
return FALSE;
}
@@ -206,7 +209,9 @@ generate_and_write_nonce (const DBusString *filename, DBusError *error)
* indicate whether the server accepted the nonce.
*/
dbus_bool_t
-_dbus_send_nonce (int fd, const DBusString *noncefile, DBusError *error)
+_dbus_send_nonce (DBusSocket fd,
+ const DBusString *noncefile,
+ DBusError *error)
{
dbus_bool_t read_result;
int send_result;
@@ -266,9 +271,8 @@ do_noncefile_create (DBusNonceFile *noncefile,
goto on_error;
}
- if (!_dbus_generate_random_ascii (&randomStr, 8))
+ if (!_dbus_generate_random_ascii (&randomStr, 8, error))
{
- dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto on_error;
}
@@ -433,7 +437,7 @@ _dbus_noncefile_get_path (const DBusNonceFile *noncefile)
* and matches the nonce from the given nonce file
*/
dbus_bool_t
-_dbus_noncefile_check_nonce (int fd,
+_dbus_noncefile_check_nonce (DBusSocket fd,
const DBusNonceFile *noncefile,
DBusError* error)
{
diff --git a/dbus/dbus-nonce.h b/dbus/dbus-nonce.h
index 474ea728..99366fd4 100644
--- a/dbus/dbus-nonce.h
+++ b/dbus/dbus-nonce.h
@@ -27,6 +27,7 @@
#include <dbus/dbus-types.h>
#include <dbus/dbus-errors.h>
#include <dbus/dbus-string.h>
+#include <dbus/dbus-sysdeps.h>
DBUS_BEGIN_DECLS
@@ -46,13 +47,13 @@ dbus_bool_t _dbus_noncefile_create (DBusNonceFile *noncefile,
dbus_bool_t _dbus_noncefile_delete (DBusNonceFile *noncefile,
DBusError *error);
-dbus_bool_t _dbus_noncefile_check_nonce (int fd,
+dbus_bool_t _dbus_noncefile_check_nonce (DBusSocket fd,
const DBusNonceFile *noncefile,
DBusError *error);
const DBusString* _dbus_noncefile_get_path (const DBusNonceFile *noncefile);
-int _dbus_accept_with_noncefile (int listen_fd,
+DBusSocket _dbus_accept_with_noncefile(DBusSocket listen_fd,
const DBusNonceFile *noncefile);
// shared
@@ -63,7 +64,7 @@ dbus_bool_t _dbus_read_nonce (const DBusString *fname,
// client
-dbus_bool_t _dbus_send_nonce (int fd,
+dbus_bool_t _dbus_send_nonce (DBusSocket fd,
const DBusString *noncefile,
DBusError *error);
diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c
index d256018e..e2a3b737 100644
--- a/dbus/dbus-object-tree.c
+++ b/dbus/dbus-object-tree.c
@@ -319,6 +319,7 @@ find_subtree_recurse (DBusObjectSubtree *subtree,
}
}
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
static DBusObjectSubtree*
find_subtree (DBusObjectTree *tree,
const char **path,
@@ -337,6 +338,7 @@ find_subtree (DBusObjectTree *tree,
else
return subtree;
}
+#endif
static DBusObjectSubtree*
lookup_subtree (DBusObjectTree *tree,
diff --git a/dbus/dbus-pending-call-internal.h b/dbus/dbus-pending-call-internal.h
index 1875eea8..393e6608 100644
--- a/dbus/dbus-pending-call-internal.h
+++ b/dbus/dbus-pending-call-internal.h
@@ -51,10 +51,13 @@ void _dbus_pending_call_set_reply_serial_unlocked (DBusPendingCal
dbus_bool_t _dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending,
DBusMessage *message,
dbus_uint32_t serial);
+DBUS_PRIVATE_EXPORT
DBusPendingCall* _dbus_pending_call_new_unlocked (DBusConnection *connection,
int timeout_milliseconds,
DBusTimeoutHandler timeout_handler);
+DBUS_PRIVATE_EXPORT
DBusPendingCall* _dbus_pending_call_ref_unlocked (DBusPendingCall *pending);
+DBUS_PRIVATE_EXPORT
void _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending);
dbus_bool_t _dbus_pending_call_set_data_unlocked (DBusPendingCall *pending,
dbus_int32_t slot,
diff --git a/dbus/dbus-pipe.h b/dbus/dbus-pipe.h
index c2063b5a..ca924ccc 100644
--- a/dbus/dbus-pipe.h
+++ b/dbus/dbus-pipe.h
@@ -42,18 +42,25 @@ struct DBusPipe {
int fd;
};
+DBUS_PRIVATE_EXPORT
void _dbus_pipe_init (DBusPipe *pipe,
int fd);
+DBUS_PRIVATE_EXPORT
void _dbus_pipe_init_stdout (DBusPipe *pipe);
+DBUS_PRIVATE_EXPORT
int _dbus_pipe_write (DBusPipe *pipe,
const DBusString *buffer,
int start,
int len,
DBusError *error);
+DBUS_PRIVATE_EXPORT
int _dbus_pipe_close (DBusPipe *pipe,
DBusError *error);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_pipe_is_valid (DBusPipe *pipe);
+DBUS_PRIVATE_EXPORT
void _dbus_pipe_invalidate (DBusPipe *pipe);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_pipe_is_stdout_or_stderr (DBusPipe *pipe);
#endif
diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h
index 60605ab2..933c3658 100644
--- a/dbus/dbus-protocol.h
+++ b/dbus/dbus-protocol.h
@@ -254,6 +254,11 @@ extern "C" {
* message.
*/
#define DBUS_HEADER_FLAG_NO_AUTO_START 0x2
+/**
+ * If set on a method call, this flag means that the caller is prepared to
+ * wait for interactive authorization.
+ */
+#define DBUS_HEADER_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION 0x4
/* Header fields */
@@ -446,6 +451,10 @@ extern "C" {
/** The message meta data does not match the payload. e.g. expected
number of file descriptors were not sent over the socket this message was received on. */
#define DBUS_ERROR_INCONSISTENT_MESSAGE "org.freedesktop.DBus.Error.InconsistentMessage"
+/** The message is not allowed without performing interactive authorization,
+ * but could have succeeded if an interactive authorization step was
+ * allowed. */
+#define DBUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED "org.freedesktop.DBus.Error.InteractiveAuthorizationRequired"
/* XML introspection format */
diff --git a/dbus/dbus-server-debug-pipe.c b/dbus/dbus-server-debug-pipe.c
index 8f5ff5fb..ca0be876 100644
--- a/dbus/dbus-server-debug-pipe.c
+++ b/dbus/dbus-server-debug-pipe.c
@@ -166,8 +166,9 @@ _dbus_server_debug_pipe_new (const char *server_name,
goto nomem_2;
if (!_dbus_server_init_base (&debug_server->base,
- &debug_vtable, &address))
- goto nomem_3;
+ &debug_vtable, &address,
+ error))
+ goto fail_3;
if (!_dbus_hash_table_insert_string (server_pipe_hash,
debug_server->name,
@@ -183,7 +184,7 @@ _dbus_server_debug_pipe_new (const char *server_name,
nomem_4:
_dbus_server_finalize_base (&debug_server->base);
- nomem_3:
+ fail_3:
dbus_free (debug_server->name);
nomem_2:
_dbus_string_free (&address);
@@ -191,7 +192,8 @@ _dbus_server_debug_pipe_new (const char *server_name,
dbus_free (debug_server);
nomem_0:
pipe_hash_unref ();
- dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ if (error != NULL && !dbus_error_is_set (error))
+ _DBUS_SET_OOM (error);
return NULL;
}
@@ -211,7 +213,7 @@ _dbus_transport_debug_pipe_new (const char *server_name,
DBusTransport *client_transport;
DBusTransport *server_transport;
DBusConnection *connection;
- int client_fd, server_fd;
+ DBusSocket client_fd, server_fd;
DBusServer *server;
DBusString address;
@@ -246,8 +248,7 @@ _dbus_transport_debug_pipe_new (const char *server_name,
return NULL;
}
- if (!_dbus_full_duplex_pipe (&client_fd, &server_fd, FALSE,
- NULL))
+ if (!_dbus_socketpair (&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");
@@ -268,7 +269,7 @@ _dbus_transport_debug_pipe_new (const char *server_name,
_dbus_string_free (&address);
- client_fd = -1;
+ _dbus_socket_invalidate (&client_fd);
server_transport = _dbus_transport_new_for_socket (server_fd,
&server->guid_hex, NULL);
@@ -280,7 +281,7 @@ _dbus_transport_debug_pipe_new (const char *server_name,
return NULL;
}
- server_fd = -1;
+ _dbus_socket_invalidate (&server_fd);
if (!_dbus_transport_set_auth_mechanisms (server_transport,
(const char**) server->auth_mechanisms))
diff --git a/dbus/dbus-server-launchd.c b/dbus/dbus-server-launchd.c
index 9832875e..818ba8cf 100644
--- a/dbus/dbus-server-launchd.c
+++ b/dbus/dbus-server-launchd.c
@@ -42,6 +42,7 @@
#include "dbus-misc.h"
#include "dbus-server-socket.h"
+#include "dbus-sysdeps-unix.h"
/* put other private launchd functions here */
@@ -184,11 +185,9 @@ _dbus_server_new_for_launchd (const char *launchd_env_var, DBusError * error)
}
- server = _dbus_server_new_for_socket (&launchd_fd, 1, &address, 0);
+ server = _dbus_server_new_for_socket (&launchd_fd, 1, &address, 0, error);
if (server == NULL)
{
- dbus_set_error (error, DBUS_ERROR_NO_SERVER,
- "Unable to listen on launchd fd %d.", launchd_fd);
goto l_failed_0;
}
diff --git a/dbus/dbus-server-protected.h b/dbus/dbus-server-protected.h
index e6dbd1e1..f613bf34 100644
--- a/dbus/dbus-server-protected.h
+++ b/dbus/dbus-server-protected.h
@@ -93,12 +93,14 @@ struct DBusServer
dbus_bool_t _dbus_server_init_base (DBusServer *server,
const DBusServerVTable *vtable,
- const DBusString *address);
+ const DBusString *address,
+ DBusError *error);
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);
+DBUS_PRIVATE_EXPORT
void _dbus_server_toggle_all_watches (DBusServer *server,
dbus_bool_t enabled);
dbus_bool_t _dbus_server_add_timeout (DBusServer *server,
@@ -109,7 +111,9 @@ void _dbus_server_toggle_timeout (DBusServer *server,
DBusTimeout *timeout,
dbus_bool_t enabled);
+DBUS_PRIVATE_EXPORT
void _dbus_server_ref_unlocked (DBusServer *server);
+DBUS_PRIVATE_EXPORT
void _dbus_server_unref_unlocked (DBusServer *server);
typedef enum
diff --git a/dbus/dbus-server-socket.c b/dbus/dbus-server-socket.c
index 060a919e..d716f500 100644
--- a/dbus/dbus-server-socket.c
+++ b/dbus/dbus-server-socket.c
@@ -51,7 +51,7 @@ struct DBusServerSocket
{
DBusServer base; /**< Parent class members. */
int n_fds; /**< Number of active file handles */
- int *fds; /**< File descriptor or -1 if disconnected. */
+ DBusSocket *fds; /**< File descriptor or DBUS_SOCKET_INVALID if disconnected. */
DBusWatch **watch; /**< File descriptor watch. */
char *socket_name; /**< Name of domain socket, to unlink if appropriate */
DBusNonceFile *noncefile; /**< Nonce file used to authenticate clients */
@@ -84,18 +84,19 @@ socket_finalize (DBusServer *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)
+ DBusSocket 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);
+ _dbus_verbose ("Creating new client connection with fd %" DBUS_SOCKET_FORMAT "\n",
+ _dbus_socket_printable (client_fd));
HAVE_LOCK_CHECK (server);
- if (!_dbus_set_fd_nonblocking (client_fd, NULL))
+ if (!_dbus_set_socket_nonblocking (client_fd, NULL))
{
SERVER_UNLOCK (server);
return TRUE;
@@ -182,25 +183,28 @@ socket_handle_watch (DBusWatch *watch,
if (flags & DBUS_WATCH_READABLE)
{
- int client_fd;
- int listen_fd;
+ DBusSocket client_fd;
+ DBusSocket listen_fd;
+ int saved_errno;
- listen_fd = dbus_watch_get_socket (watch);
+ listen_fd = _dbus_watch_get_socket (watch);
if (socket_server->noncefile)
client_fd = _dbus_accept_with_noncefile (listen_fd, socket_server->noncefile);
else
client_fd = _dbus_accept (listen_fd);
- if (client_fd < 0)
+ saved_errno = _dbus_save_socket_errno ();
+
+ if (!_dbus_socket_is_valid (client_fd))
{
/* EINTR handled for us */
- if (_dbus_get_is_errno_eagain_or_ewouldblock ())
+ if (_dbus_get_is_errno_eagain_or_ewouldblock (saved_errno))
_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 ());
+ _dbus_strerror (saved_errno));
SERVER_UNLOCK (server);
}
@@ -240,7 +244,7 @@ socket_disconnect (DBusServer *server)
}
_dbus_close_socket (socket_server->fds[i], NULL);
- socket_server->fds[i] = -1;
+ _dbus_socket_invalidate (&socket_server->fds[i]);
}
if (socket_server->socket_name != NULL)
@@ -273,14 +277,16 @@ static const DBusServerVTable socket_vtable = {
* @param n_fds number of file descriptors
* @param address the server's address
* @param noncefile to be used for authentication (NULL if not needed)
- * @returns the new server, or #NULL if no memory.
+ * @param error location to store reason for failure
+ * @returns the new server, or #NULL on OOM or other error.
*
*/
DBusServer*
-_dbus_server_new_for_socket (int *fds,
+_dbus_server_new_for_socket (DBusSocket *fds,
int n_fds,
const DBusString *address,
- DBusNonceFile *noncefile)
+ DBusNonceFile *noncefile,
+ DBusError *error)
{
DBusServerSocket *socket_server;
DBusServer *server;
@@ -288,11 +294,11 @@ _dbus_server_new_for_socket (int *fds,
socket_server = dbus_new0 (DBusServerSocket, 1);
if (socket_server == NULL)
- return NULL;
+ goto failed_0;
socket_server->noncefile = noncefile;
- socket_server->fds = dbus_new (int, n_fds);
+ socket_server->fds = dbus_new (DBusSocket, n_fds);
if (!socket_server->fds)
goto failed_0;
@@ -304,7 +310,7 @@ _dbus_server_new_for_socket (int *fds,
{
DBusWatch *watch;
- watch = _dbus_watch_new (fds[i],
+ watch = _dbus_watch_new (_dbus_socket_get_pollable (fds[i]),
DBUS_WATCH_READABLE,
TRUE,
socket_handle_watch, socket_server,
@@ -318,7 +324,8 @@ _dbus_server_new_for_socket (int *fds,
}
if (!_dbus_server_init_base (&socket_server->base,
- &socket_vtable, address))
+ &socket_vtable, address,
+ error))
goto failed_2;
server = (DBusServer*)socket_server;
@@ -362,6 +369,10 @@ _dbus_server_new_for_socket (int *fds,
failed_0:
dbus_free (socket_server);
+
+ if (error != NULL && !dbus_error_is_set (error))
+ _DBUS_SET_OOM (error);
+
return NULL;
}
@@ -393,7 +404,7 @@ _dbus_server_new_for_tcp_socket (const char *host,
dbus_bool_t use_nonce)
{
DBusServer *server;
- int *listen_fds = NULL;
+ DBusSocket *listen_fds = NULL;
int nlisten_fds = 0, i;
DBusString address;
DBusString host_str;
@@ -474,10 +485,9 @@ _dbus_server_new_for_tcp_socket (const char *host,
}
- server = _dbus_server_new_for_socket (listen_fds, nlisten_fds, &address, noncefile);
+ server = _dbus_server_new_for_socket (listen_fds, nlisten_fds, &address, noncefile, error);
if (server == NULL)
{
- dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
if (noncefile != NULL)
goto failed_4;
else
diff --git a/dbus/dbus-server-socket.h b/dbus/dbus-server-socket.h
index 3aec7129..1a589f7d 100644
--- a/dbus/dbus-server-socket.h
+++ b/dbus/dbus-server-socket.h
@@ -29,12 +29,14 @@
DBUS_BEGIN_DECLS
-DBusServer* _dbus_server_new_for_socket (int *fds,
+DBusServer* _dbus_server_new_for_socket (DBusSocket *fds,
int n_fds,
const DBusString *address,
- DBusNonceFile *noncefile);
+ DBusNonceFile *noncefile,
+ DBusError *error);
DBusServer* _dbus_server_new_for_autolaunch (const DBusString *address,
DBusError *error);
+DBUS_PRIVATE_EXPORT
DBusServer* _dbus_server_new_for_tcp_socket (const char *host,
const char *bind,
const char *port,
diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c
index d9952404..92664a8d 100644
--- a/dbus/dbus-server-unix.c
+++ b/dbus/dbus-server-unix.c
@@ -66,25 +66,75 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
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");
+ const char *runtime = dbus_address_entry_get_value (entry, "runtime");
+ int mutually_exclusive_modes = 0;
- if (path == NULL && tmpdir == NULL && abstract == NULL)
+ mutually_exclusive_modes = (path != NULL) + (tmpdir != NULL) +
+ (abstract != NULL) + (runtime != NULL);
+
+ if (mutually_exclusive_modes < 1)
{
_dbus_set_bad_address(error, "unix",
- "path or tmpdir or abstract",
+ "path or tmpdir or abstract or runtime",
NULL);
return DBUS_SERVER_LISTEN_BAD_ADDRESS;
}
- if ((path && tmpdir) ||
- (path && abstract) ||
- (tmpdir && abstract))
+ if (mutually_exclusive_modes > 1)
{
_dbus_set_bad_address(error, NULL, NULL,
- "cannot specify two of \"path\" and \"tmpdir\" and \"abstract\" at the same time");
+ "cannot specify two of \"path\", \"tmpdir\", \"abstract\" and \"runtime\" at the same time");
return DBUS_SERVER_LISTEN_BAD_ADDRESS;
}
- if (tmpdir != NULL)
+ if (runtime != NULL)
+ {
+ DBusString full_path;
+ DBusString filename;
+ const char *runtimedir;
+
+ if (strcmp (runtime, "yes") != 0)
+ {
+ _dbus_set_bad_address(error, NULL, NULL,
+ "if given, the only value allowed for \"runtime\" is \"yes\"");
+ return DBUS_SERVER_LISTEN_BAD_ADDRESS;
+ }
+
+ runtimedir = _dbus_getenv ("XDG_RUNTIME_DIR");
+
+ if (runtimedir == NULL)
+ {
+ dbus_set_error (error,
+ DBUS_ERROR_NOT_SUPPORTED, "\"XDG_RUNTIME_DIR\" is not set");
+ return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
+ }
+
+ _dbus_string_init_const (&filename, "bus");
+
+ if (!_dbus_string_init (&full_path))
+ {
+ _DBUS_SET_OOM (error);
+ return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
+ }
+
+ if (!_dbus_string_append (&full_path, runtimedir) ||
+ !_dbus_concat_dir_and_file (&full_path, &filename))
+ {
+ _dbus_string_free (&full_path);
+ _DBUS_SET_OOM (error);
+ return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
+ }
+
+ /* We can safely use filesystem sockets in the runtime directory,
+ * and they are preferred because they can be bind-mounted between
+ * Linux containers. */
+ *server_p = _dbus_server_new_for_domain_socket (
+ _dbus_string_get_const_data (&full_path),
+ FALSE, error);
+
+ _dbus_string_free (&full_path);
+ }
+ else if (tmpdir != NULL)
{
DBusString full_path;
DBusString filename;
@@ -102,10 +152,22 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
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) ||
+ if (!_dbus_string_append (&filename, "dbus-"))
+ {
+ _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;
+ }
+
+ if (!_dbus_generate_random_ascii (&filename, 10, error))
+ {
+ _dbus_string_free (&full_path);
+ _dbus_string_free (&filename);
+ return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
+ }
+
+ if (!_dbus_string_append (&full_path, tmpdir) ||
!_dbus_concat_dir_and_file (&full_path, &filename))
{
_dbus_string_free (&full_path);
@@ -149,7 +211,8 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
}
else if (strcmp (method, "systemd") == 0)
{
- int i, n, *fds;
+ int i, n;
+ DBusSocket *fds;
DBusString address;
n = _dbus_listen_systemd_sockets (&fds, error);
@@ -173,13 +236,14 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
goto systemd_err;
}
- *server_p = _dbus_server_new_for_socket (fds, n, &address, NULL);
+ *server_p = _dbus_server_new_for_socket (fds, n, &address, NULL, error);
if (*server_p == NULL)
- goto systemd_oom;
+ goto systemd_err;
dbus_free (fds);
return DBUS_SERVER_LISTEN_OK;
+
systemd_oom:
_DBUS_SET_OOM (error);
systemd_err:
@@ -239,7 +303,7 @@ _dbus_server_new_for_domain_socket (const char *path,
DBusError *error)
{
DBusServer *server;
- int listen_fd;
+ DBusSocket listen_fd;
DBusString address;
char *path_copy;
DBusString path_str;
@@ -277,18 +341,17 @@ _dbus_server_new_for_domain_socket (const char *path,
}
}
- listen_fd = _dbus_listen_unix_socket (path, abstract, error);
+ listen_fd.fd = _dbus_listen_unix_socket (path, abstract, error);
- if (listen_fd < 0)
+ if (listen_fd.fd < 0)
{
_DBUS_ASSERT_ERROR_IS_SET (error);
goto failed_1;
}
- server = _dbus_server_new_for_socket (&listen_fd, 1, &address, 0);
+ server = _dbus_server_new_for_socket (&listen_fd, 1, &address, 0, error);
if (server == NULL)
{
- dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed_2;
}
diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c
index 7b810792..9af906fa 100644
--- a/dbus/dbus-server.c
+++ b/dbus/dbus-server.c
@@ -105,12 +105,14 @@ copy_address_with_guid_appended (const DBusString *address,
* @param server the server.
* @param vtable the vtable for the subclass.
* @param address the server's address
+ * @param error location to store reason for failure
* @returns #TRUE on success.
*/
dbus_bool_t
_dbus_server_init_base (DBusServer *server,
const DBusServerVTable *vtable,
- const DBusString *address)
+ const DBusString *address,
+ DBusError *error)
{
server->vtable = vtable;
@@ -130,29 +132,33 @@ _dbus_server_init_base (DBusServer *server,
server->published_address = FALSE;
if (!_dbus_string_init (&server->guid_hex))
- return FALSE;
+ {
+ _DBUS_SET_OOM (error);
+ return FALSE;
+ }
- _dbus_generate_uuid (&server->guid);
+ if (!_dbus_generate_uuid (&server->guid, error))
+ goto failed;
if (!_dbus_uuid_encode (&server->guid, &server->guid_hex))
- goto failed;
+ goto oom;
server->address = copy_address_with_guid_appended (address,
&server->guid_hex);
if (server->address == NULL)
- goto failed;
+ goto oom;
_dbus_rmutex_new_at_location (&server->mutex);
if (server->mutex == NULL)
- goto failed;
+ goto oom;
server->watches = _dbus_watch_list_new ();
if (server->watches == NULL)
- goto failed;
+ goto oom;
server->timeouts = _dbus_timeout_list_new ();
if (server->timeouts == NULL)
- goto failed;
+ goto oom;
_dbus_data_slot_list_init (&server->slot_list);
@@ -160,6 +166,8 @@ _dbus_server_init_base (DBusServer *server,
return TRUE;
+ oom:
+ _DBUS_SET_OOM (error);
failed:
_dbus_rmutex_free_at_location (&server->mutex);
server->mutex = NULL;
diff --git a/dbus/dbus-shared.h b/dbus/dbus-shared.h
index 6a576704..7ab91035 100644
--- a/dbus/dbus-shared.h
+++ b/dbus/dbus-shared.h
@@ -86,6 +86,11 @@ typedef enum
*/
/** The interface exported by the object with #DBUS_SERVICE_DBUS and #DBUS_PATH_DBUS */
#define DBUS_INTERFACE_DBUS "org.freedesktop.DBus"
+/** The monitoring interface exported by the dbus-daemon */
+#define DBUS_INTERFACE_MONITORING "org.freedesktop.DBus.Monitoring"
+
+/** The verbose interface exported by the dbus-daemon */
+#define DBUS_INTERFACE_VERBOSE "org.freedesktop.DBus.Verbose"
/** The interface supported by introspectable objects */
#define DBUS_INTERFACE_INTROSPECTABLE "org.freedesktop.DBus.Introspectable"
/** The interface supported by objects with properties */
diff --git a/dbus/dbus-signature.c b/dbus/dbus-signature.c
index 8a4701c9..6f1521b1 100644
--- a/dbus/dbus-signature.c
+++ b/dbus/dbus-signature.c
@@ -428,7 +428,7 @@ _dbus_signature_test (void)
const char *sig;
dbus_bool_t boolres;
- _dbus_assert (sizeof (DBusSignatureIter) >= sizeof (DBusSignatureRealIter));
+ _DBUS_STATIC_ASSERT (sizeof (DBusSignatureIter) >= sizeof (DBusSignatureRealIter));
sig = "";
_dbus_assert (dbus_signature_validate (sig, NULL));
diff --git a/dbus/dbus-socket-set-epoll.c b/dbus/dbus-socket-set-epoll.c
index 4cd9a563..aedc26df 100644
--- a/dbus/dbus-socket-set-epoll.c
+++ b/dbus/dbus-socket-set-epoll.c
@@ -136,7 +136,7 @@ epoll_events_to_watch_flags (uint32_t events)
static dbus_bool_t
socket_set_epoll_add (DBusSocketSet *set,
- int fd,
+ DBusPollable fd,
unsigned int flags,
dbus_bool_t enabled)
{
@@ -189,7 +189,7 @@ socket_set_epoll_add (DBusSocketSet *set,
static void
socket_set_epoll_enable (DBusSocketSet *set,
- int fd,
+ DBusPollable fd,
unsigned int flags)
{
DBusSocketSetEpoll *self = socket_set_epoll_cast (set);
@@ -229,7 +229,7 @@ socket_set_epoll_enable (DBusSocketSet *set,
static void
socket_set_epoll_disable (DBusSocketSet *set,
- int fd)
+ DBusPollable fd)
{
DBusSocketSetEpoll *self = socket_set_epoll_cast (set);
struct epoll_event event;
@@ -264,7 +264,7 @@ socket_set_epoll_disable (DBusSocketSet *set,
static void
socket_set_epoll_remove (DBusSocketSet *set,
- int fd)
+ DBusPollable fd)
{
DBusSocketSetEpoll *self = socket_set_epoll_cast (set);
int err;
diff --git a/dbus/dbus-socket-set-poll.c b/dbus/dbus-socket-set-poll.c
index e322a3b4..623e28fa 100644
--- a/dbus/dbus-socket-set-poll.c
+++ b/dbus/dbus-socket-set-poll.c
@@ -114,7 +114,7 @@ watch_flags_to_poll_events (unsigned int flags)
static dbus_bool_t
socket_set_poll_add (DBusSocketSet *set,
- int fd,
+ DBusPollable fd,
unsigned int flags,
dbus_bool_t enabled)
{
@@ -123,7 +123,7 @@ socket_set_poll_add (DBusSocketSet *set,
int i;
for (i = 0; i < self->n_fds; i++)
- _dbus_assert (self->fds[i].fd != fd);
+ _dbus_assert (!_dbus_pollable_equals (self->fds[i].fd, fd));
#endif
if (self->n_reserved >= self->n_allocated)
@@ -142,8 +142,8 @@ socket_set_poll_add (DBusSocketSet *set,
self->n_allocated += REALLOC_INCREMENT;
}
- _dbus_verbose ("before adding fd %d to %p, %d en/%d res/%d alloc\n",
- fd, self, self->n_fds, self->n_reserved, self->n_allocated);
+ _dbus_verbose ("before adding fd %" DBUS_POLLABLE_FORMAT " to %p, %d en/%d res/%d alloc\n",
+ _dbus_pollable_printable (fd), self, self->n_fds, self->n_reserved, self->n_allocated);
_dbus_assert (self->n_reserved >= self->n_fds);
_dbus_assert (self->n_allocated > self->n_reserved);
@@ -161,7 +161,7 @@ socket_set_poll_add (DBusSocketSet *set,
static void
socket_set_poll_enable (DBusSocketSet *set,
- int fd,
+ DBusPollable fd,
unsigned int flags)
{
DBusSocketSetPoll *self = socket_set_poll_cast (set);
@@ -169,7 +169,7 @@ socket_set_poll_enable (DBusSocketSet *set,
for (i = 0; i < self->n_fds; i++)
{
- if (self->fds[i].fd == fd)
+ if (_dbus_pollable_equals (self->fds[i].fd, fd))
{
self->fds[i].events = watch_flags_to_poll_events (flags);
return;
@@ -187,14 +187,14 @@ socket_set_poll_enable (DBusSocketSet *set,
static void
socket_set_poll_disable (DBusSocketSet *set,
- int fd)
+ DBusPollable fd)
{
DBusSocketSetPoll *self = socket_set_poll_cast (set);
int i;
for (i = 0; i < self->n_fds; i++)
{
- if (self->fds[i].fd == fd)
+ if (_dbus_pollable_equals (self->fds[i].fd, fd))
{
if (i != self->n_fds - 1)
{
@@ -210,15 +210,15 @@ socket_set_poll_disable (DBusSocketSet *set,
static void
socket_set_poll_remove (DBusSocketSet *set,
- int fd)
+ DBusPollable fd)
{
DBusSocketSetPoll *self = socket_set_poll_cast (set);
socket_set_poll_disable (set, fd);
self->n_reserved--;
- _dbus_verbose ("after removing fd %d from %p, %d en/%d res/%d alloc\n",
- fd, self, self->n_fds, self->n_reserved, self->n_allocated);
+ _dbus_verbose ("after removing fd %" DBUS_POLLABLE_FORMAT " from %p, %d en/%d res/%d alloc\n",
+ _dbus_pollable_printable (fd), self, self->n_fds, self->n_reserved, self->n_allocated);
_dbus_assert (self->n_fds <= self->n_reserved);
_dbus_assert (self->n_reserved <= self->n_allocated);
diff --git a/dbus/dbus-socket-set.h b/dbus/dbus-socket-set.h
index 3b71a925..bcc263a7 100644
--- a/dbus/dbus-socket-set.h
+++ b/dbus/dbus-socket-set.h
@@ -29,9 +29,10 @@
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#include <dbus/dbus.h>
+#include <dbus/dbus-sysdeps.h>
typedef struct {
- int fd;
+ DBusPollable fd;
unsigned int flags;
} DBusSocketEvent;
@@ -41,16 +42,16 @@ typedef struct DBusSocketSetClass DBusSocketSetClass;
struct DBusSocketSetClass {
void (*free) (DBusSocketSet *self);
dbus_bool_t (*add) (DBusSocketSet *self,
- int fd,
+ DBusPollable fd,
unsigned int flags,
dbus_bool_t enabled);
void (*remove) (DBusSocketSet *self,
- int fd);
+ DBusPollable fd);
void (*enable) (DBusSocketSet *self,
- int fd,
+ DBusPollable fd,
unsigned int flags);
void (*disable) (DBusSocketSet *self,
- int fd);
+ DBusPollable fd);
int (*poll) (DBusSocketSet *self,
DBusSocketEvent *revents,
int max_events,
@@ -71,7 +72,7 @@ _dbus_socket_set_free (DBusSocketSet *self)
static inline dbus_bool_t
_dbus_socket_set_add (DBusSocketSet *self,
- int fd,
+ DBusPollable fd,
unsigned int flags,
dbus_bool_t enabled)
{
@@ -80,14 +81,14 @@ _dbus_socket_set_add (DBusSocketSet *self,
static inline void
_dbus_socket_set_remove (DBusSocketSet *self,
- int fd)
+ DBusPollable fd)
{
(self->cls->remove) (self, fd);
}
static inline void
_dbus_socket_set_enable (DBusSocketSet *self,
- int fd,
+ DBusPollable fd,
unsigned int flags)
{
(self->cls->enable) (self, fd, flags);
@@ -95,7 +96,7 @@ _dbus_socket_set_enable (DBusSocketSet *self,
static inline void
_dbus_socket_set_disable (DBusSocketSet *self,
- int fd)
+ DBusPollable fd)
{
(self->cls->disable) (self, fd);
}
diff --git a/dbus/dbus-sockets-win.h b/dbus/dbus-sockets-win.h
index 4e1ab8ca..a35d6537 100644
--- a/dbus/dbus-sockets-win.h
+++ b/dbus/dbus-sockets-win.h
@@ -41,25 +41,12 @@
#include <errno.h>
#endif
-#define DBUS_SOCKET_IS_INVALID(s) ((SOCKET)(s) == INVALID_SOCKET)
#define DBUS_SOCKET_API_RETURNS_ERROR(n) ((n) == SOCKET_ERROR)
#define DBUS_SOCKET_SET_ERRNO() (_dbus_win_set_errno (WSAGetLastError()))
-#define DBUS_CLOSE_SOCKET(s) closesocket(s)
-
#else
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <errno.h>
-
-#define DBUS_SOCKET_IS_INVALID(s) ((s) < 0)
-#define DBUS_SOCKET_API_RETURNS_ERROR(n) ((n) < 0)
-#define DBUS_SOCKET_SET_ERRNO() /* empty */
-
-#define DBUS_CLOSE_SOCKET(s) close(s)
+#error "dbus-sockets-win.h should not be included on non-Windows"
#endif /* !Win32 */
diff --git a/dbus/dbus-spawn-win.c b/dbus/dbus-spawn-win.c
index 7da7a431..7f68f14e 100644
--- a/dbus/dbus-spawn-win.c
+++ b/dbus/dbus-spawn-win.c
@@ -77,8 +77,8 @@ struct DBusBabysitter
char **envp;
HANDLE child_handle;
- int socket_to_babysitter; /* Connection to the babysitter thread */
- int socket_to_main;
+ DBusSocket socket_to_babysitter; /* Connection to the babysitter thread */
+ DBusSocket socket_to_main;
DBusWatchList *watches;
DBusWatch *sitter_watch;
@@ -120,7 +120,7 @@ _dbus_babysitter_new (void)
sitter->child_handle = NULL;
- sitter->socket_to_babysitter = sitter->socket_to_main = -1;
+ sitter->socket_to_babysitter = sitter->socket_to_main = _dbus_socket_get_invalid ();
sitter->argc = 0;
sitter->argv = NULL;
@@ -171,10 +171,10 @@ close_socket_to_babysitter (DBusBabysitter *sitter)
sitter->sitter_watch = NULL;
}
- if (sitter->socket_to_babysitter != -1)
+ if (sitter->socket_to_babysitter.sock != INVALID_SOCKET)
{
_dbus_close_socket (sitter->socket_to_babysitter, NULL);
- sitter->socket_to_babysitter = -1;
+ sitter->socket_to_babysitter.sock = INVALID_SOCKET;
}
}
@@ -198,10 +198,10 @@ _dbus_babysitter_unref (DBusBabysitter *sitter)
{
close_socket_to_babysitter (sitter);
- if (sitter->socket_to_main != -1)
+ if (sitter->socket_to_main.sock != INVALID_SOCKET)
{
_dbus_close_socket (sitter->socket_to_main, NULL);
- sitter->socket_to_main = -1;
+ sitter->socket_to_main.sock = INVALID_SOCKET;
}
PING();
@@ -633,7 +633,7 @@ babysitter (void *parameter)
#endif
PING();
- send (sitter->socket_to_main, " ", 1, 0);
+ send (sitter->socket_to_main.sock, " ", 1, 0);
_dbus_babysitter_unref (sitter);
@@ -686,9 +686,9 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
}
PING();
- if (!_dbus_full_duplex_pipe (&sitter->socket_to_babysitter,
- &sitter->socket_to_main,
- FALSE, error))
+ if (!_dbus_socketpair (&sitter->socket_to_babysitter,
+ &sitter->socket_to_main,
+ FALSE, error))
goto out0;
sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter,
diff --git a/dbus/dbus-spawn.c b/dbus/dbus-spawn.c
index b95cad6e..ddd254dc 100644
--- a/dbus/dbus-spawn.c
+++ b/dbus/dbus-spawn.c
@@ -243,7 +243,7 @@ struct DBusBabysitter
char *log_name; /**< the name under which to log messages about this
process being spawned */
- int socket_to_babysitter; /**< Connection to the babysitter process */
+ DBusSocket 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 */
@@ -275,7 +275,7 @@ _dbus_babysitter_new (void)
sitter->refcount = 1;
- sitter->socket_to_babysitter = -1;
+ sitter->socket_to_babysitter.fd = -1;
sitter->error_pipe_from_child = -1;
sitter->sitter_pid = -1;
@@ -454,9 +454,25 @@ read_data (DBusBabysitter *sitter,
{
if (what == CHILD_EXITED)
{
+ /* Do not reset sitter->errnum to 0 here. We get here if
+ * the babysitter reports that the grandchild process has
+ * exited, and there are two ways that can happen:
+ *
+ * 1. grandchild successfully exec()s the desired process,
+ * but then the desired process exits or is terminated
+ * by a signal. The babysitter observes this and reports
+ * CHILD_EXITED.
+ *
+ * 2. grandchild fails to exec() the desired process,
+ * attempts to report the exec() failure (which
+ * we will receive as CHILD_EXEC_FAILED), and then
+ * exits itself (which will prompt the babysitter to
+ * send CHILD_EXITED). We want the CHILD_EXEC_FAILED
+ * to take precedence (and have its errno logged),
+ * which _dbus_babysitter_set_child_exit_error() does.
+ */
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));
@@ -522,10 +538,10 @@ close_socket_to_babysitter (DBusBabysitter *sitter)
sitter->sitter_watch = NULL;
}
- if (sitter->socket_to_babysitter >= 0)
+ if (sitter->socket_to_babysitter.fd >= 0)
{
_dbus_close_socket (sitter->socket_to_babysitter, NULL);
- sitter->socket_to_babysitter = -1;
+ sitter->socket_to_babysitter.fd = -1;
}
}
@@ -545,7 +561,7 @@ close_error_pipe_from_child (DBusBabysitter *sitter)
if (sitter->error_pipe_from_child >= 0)
{
- _dbus_close_socket (sitter->error_pipe_from_child, NULL);
+ _dbus_close (sitter->error_pipe_from_child, NULL);
sitter->error_pipe_from_child = -1;
}
}
@@ -561,7 +577,7 @@ handle_babysitter_socket (DBusBabysitter *sitter,
if (revents & _DBUS_POLLIN)
{
_dbus_verbose ("Reading data from babysitter\n");
- if (read_data (sitter, sitter->socket_to_babysitter) != READ_STATUS_OK)
+ if (read_data (sitter, sitter->socket_to_babysitter.fd) != READ_STATUS_OK)
close_socket_to_babysitter (sitter);
}
else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
@@ -607,9 +623,9 @@ babysitter_iteration (DBusBabysitter *sitter,
++i;
}
- if (sitter->socket_to_babysitter >= 0)
+ if (sitter->socket_to_babysitter.fd >= 0)
{
- fds[i].fd = sitter->socket_to_babysitter;
+ fds[i].fd = sitter->socket_to_babysitter.fd;
fds[i].events = _DBUS_POLLIN;
fds[i].revents = 0;
++i;
@@ -643,7 +659,7 @@ babysitter_iteration (DBusBabysitter *sitter,
--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)
+ else if (fds[i].fd == sitter->socket_to_babysitter.fd)
handle_babysitter_socket (sitter, fds[i].revents);
}
}
@@ -656,7 +672,7 @@ babysitter_iteration (DBusBabysitter *sitter,
* 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)
+#define LIVE_CHILDREN(sitter) ((sitter)->socket_to_babysitter.fd >= 0 || (sitter)->error_pipe_from_child >= 0)
/**
* Blocks until the babysitter process gives us the PID of the spawned grandchild,
@@ -696,7 +712,7 @@ _dbus_babysitter_get_child_exited (DBusBabysitter *sitter)
;
/* We will have exited the babysitter when the child has exited */
- return sitter->socket_to_babysitter < 0;
+ return sitter->socket_to_babysitter.fd < 0;
}
/**
@@ -830,7 +846,7 @@ handle_watch (DBusWatch *watch,
if (fd == sitter->error_pipe_from_child)
handle_error_pipe (sitter, revents);
- else if (fd == sitter->socket_to_babysitter)
+ else if (fd == sitter->socket_to_babysitter.fd)
handle_babysitter_socket (sitter, revents);
while (LIVE_CHILDREN (sitter) &&
@@ -839,7 +855,7 @@ handle_watch (DBusWatch *watch,
/* fd.o #32992: if the handle_* methods closed their sockets, they previously
* didn't always remove the watches. Check that we don't regress. */
- _dbus_assert (sitter->socket_to_babysitter != -1 || sitter->sitter_watch == NULL);
+ _dbus_assert (sitter->socket_to_babysitter.fd != -1 || sitter->sitter_watch == NULL);
_dbus_assert (sitter->error_pipe_from_child != -1 || sitter->error_watch == NULL);
if (_dbus_babysitter_get_child_exited (sitter) &&
@@ -877,7 +893,7 @@ close_and_invalidate (int *fd)
return -1;
else
{
- ret = _dbus_close_socket (*fd, NULL);
+ ret = _dbus_close (*fd, NULL);
*fd = -1;
}
@@ -1017,7 +1033,7 @@ do_exec (int child_err_report_fd,
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);
+ _dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i);
}
#endif
@@ -1201,7 +1217,7 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
{
DBusBabysitter *sitter;
int child_err_report_pipe[2] = { -1, -1 };
- int babysitter_pipe[2] = { -1, -1 };
+ DBusSocket babysitter_pipe[2] = { DBUS_SOCKET_INIT, DBUS_SOCKET_INIT };
pid_t pid;
#ifdef HAVE_SYSTEMD
int fd_out = -1;
@@ -1242,7 +1258,7 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
if (!make_pipe (child_err_report_pipe, error))
goto cleanup_and_fail;
- if (!_dbus_full_duplex_pipe (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
+ if (!_dbus_socketpair (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
goto cleanup_and_fail;
/* Setting up the babysitter is only useful in the parent,
@@ -1271,7 +1287,7 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
goto cleanup_and_fail;
}
- sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0],
+ sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0].fd,
DBUS_WATCH_READABLE,
TRUE, handle_watch, sitter, NULL);
if (sitter->sitter_watch == NULL)
@@ -1325,14 +1341,14 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
/* Close the parent's end of the pipes. */
close_and_invalidate (&child_err_report_pipe[READ_END]);
- close_and_invalidate (&babysitter_pipe[0]);
+ close_and_invalidate (&babysitter_pipe[0].fd);
/* Create the child that will exec () */
grandchild_pid = fork ();
if (grandchild_pid < 0)
{
- write_err_and_exit (babysitter_pipe[1],
+ write_err_and_exit (babysitter_pipe[1].fd,
CHILD_FORK_FAILED);
_dbus_assert_not_reached ("Got to code after write_err_and_exit()");
}
@@ -1342,7 +1358,7 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
*/
signal (SIGPIPE, SIG_IGN);
- close_and_invalidate (&babysitter_pipe[1]);
+ close_and_invalidate (&babysitter_pipe[1].fd);
#ifdef HAVE_SYSTEMD
/* log to systemd journal if possible */
if (fd_out >= 0)
@@ -1365,7 +1381,7 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
close_and_invalidate (&fd_out);
close_and_invalidate (&fd_err);
#endif
- babysit (grandchild_pid, babysitter_pipe[1]);
+ babysit (grandchild_pid, babysitter_pipe[1].fd);
_dbus_assert_not_reached ("Got to code after babysit()");
}
}
@@ -1373,14 +1389,14 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
{
/* Close the uncared-about ends of the pipes */
close_and_invalidate (&child_err_report_pipe[WRITE_END]);
- close_and_invalidate (&babysitter_pipe[1]);
+ close_and_invalidate (&babysitter_pipe[1].fd);
#ifdef HAVE_SYSTEMD
close_and_invalidate (&fd_out);
close_and_invalidate (&fd_err);
#endif
sitter->socket_to_babysitter = babysitter_pipe[0];
- babysitter_pipe[0] = -1;
+ babysitter_pipe[0].fd = -1;
sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
child_err_report_pipe[READ_END] = -1;
@@ -1405,8 +1421,8 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
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]);
+ close_and_invalidate (&babysitter_pipe[0].fd);
+ close_and_invalidate (&babysitter_pipe[1].fd);
#ifdef HAVE_SYSTEMD
close_and_invalidate (&fd_out);
close_and_invalidate (&fd_err);
diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c
index c4e2e7fc..98d9f2b7 100644
--- a/dbus/dbus-string.c
+++ b/dbus/dbus-string.c
@@ -133,11 +133,11 @@ _dbus_string_init_preallocated (DBusString *str,
int allocate_size)
{
DBusRealString *real;
-
+
+ _DBUS_STATIC_ASSERT (sizeof (DBusString) == sizeof (DBusRealString));
+
_dbus_assert (str != NULL);
- _dbus_assert (sizeof (DBusString) == sizeof (DBusRealString));
-
real = (DBusRealString*) str;
/* It's very important not to touch anything
@@ -234,6 +234,23 @@ _dbus_string_init_const_len (DBusString *str,
}
/**
+ * Initializes a string from another string. The
+ * string must eventually be freed with _dbus_string_free().
+ *
+ * @param str memory to hold the string
+ * @param from instance from which the string is initialized
+ * @returns #TRUE on success, #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_string_init_from_string(DBusString *str,
+ const DBusString *from)
+{
+ if (!_dbus_string_init (str))
+ return FALSE;
+ return _dbus_string_append (str, _dbus_string_get_const_data (from));
+}
+
+/**
* Frees a string created by _dbus_string_init().
*
* @param str memory where the string is stored.
@@ -1056,6 +1073,7 @@ _dbus_string_append_printf_valist (DBusString *str,
const char *format,
va_list args)
{
+ dbus_bool_t ret = FALSE;
int len;
va_list args_copy;
@@ -1067,21 +1085,21 @@ _dbus_string_append_printf_valist (DBusString *str,
len = _dbus_printf_string_upper_bound (format, args);
if (len < 0)
- return FALSE;
+ goto out;
if (!_dbus_string_lengthen (str, len))
{
- /* don't leak the copy */
- va_end (args_copy);
- return FALSE;
+ goto out;
}
vsprintf ((char*) (real->str + (real->len - len)),
format, args_copy);
+ ret = TRUE;
+out:
va_end (args_copy);
- return TRUE;
+ return ret;
}
/**
diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h
index 86fb8c39..adf709bd 100644
--- a/dbus/dbus-string.h
+++ b/dbus/dbus-string.h
@@ -67,54 +67,72 @@ struct DBusString
#define _dbus_string_get_const_data_len(s,start,len) (((const char*)(((DBusString*)(s))->dummy1)) + (start))
#endif
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_init (DBusString *str);
+DBUS_PRIVATE_EXPORT
void _dbus_string_init_const (DBusString *str,
const char *value);
+DBUS_PRIVATE_EXPORT
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);
+
+DBUS_PRIVATE_EXPORT
+dbus_bool_t _dbus_string_init_from_string (DBusString *str,
+ const DBusString *from);
+DBUS_PRIVATE_EXPORT
void _dbus_string_free (DBusString *str);
void _dbus_string_lock (DBusString *str);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_compact (DBusString *str,
int max_waste);
#ifndef _dbus_string_get_data
+DBUS_PRIVATE_EXPORT
char* _dbus_string_get_data (DBusString *str);
#endif /* _dbus_string_get_data */
#ifndef _dbus_string_get_const_data
+DBUS_PRIVATE_EXPORT
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
+DBUS_PRIVATE_EXPORT
const char* _dbus_string_get_const_data_len (const DBusString *str,
int start,
int len);
#endif
#ifndef _dbus_string_set_byte
+DBUS_PRIVATE_EXPORT
void _dbus_string_set_byte (DBusString *str,
int i,
unsigned char byte);
#endif
#ifndef _dbus_string_get_byte
+DBUS_PRIVATE_EXPORT
unsigned char _dbus_string_get_byte (const DBusString *str,
int start);
#endif /* _dbus_string_get_byte */
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_insert_bytes (DBusString *str,
int i,
int n_bytes,
unsigned char byte);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_insert_byte (DBusString *str,
int i,
unsigned char byte);
+DBUS_PRIVATE_EXPORT
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_PRIVATE_EXPORT
dbus_bool_t _dbus_string_copy_data (const DBusString *str,
char **data_return);
dbus_bool_t _dbus_string_copy_data_len (const DBusString *str,
@@ -124,37 +142,65 @@ dbus_bool_t _dbus_string_copy_data_len (const DBusString *str,
void _dbus_string_copy_to_buffer (const DBusString *str,
char *buffer,
int len);
+DBUS_PRIVATE_EXPORT
void _dbus_string_copy_to_buffer_with_nul (const DBusString *str,
char *buffer,
int avail_len);
#ifndef _dbus_string_get_length
+DBUS_PRIVATE_EXPORT
int _dbus_string_get_length (const DBusString *str);
#endif /* !_dbus_string_get_length */
+/**
+ * Get the string's length as an unsigned integer, for comparison with
+ * size_t and similar unsigned types that does not trigger compiler
+ * warnings about potential value changes during conversion.
+ *
+ * DBusString lengths are signed for historical reasons, but we know that
+ * the length is always >= 0 (and DBUS_GENERIC_STRING_PREAMBLE asserts
+ * that this is the case) so we know that this cast does not change the
+ * value.
+ */
+static inline unsigned int
+_dbus_string_get_length_uint (const DBusString *str)
+{
+ return (unsigned int) _dbus_string_get_length (str);
+}
+
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_lengthen (DBusString *str,
int additional_length);
+DBUS_PRIVATE_EXPORT
void _dbus_string_shorten (DBusString *str,
int length_to_remove);
+DBUS_PRIVATE_EXPORT
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_PRIVATE_EXPORT
dbus_bool_t _dbus_string_append (DBusString *str,
const char *buffer);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_append_len (DBusString *str,
const char *buffer,
int len);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_append_int (DBusString *str,
long value);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_append_uint (DBusString *str,
unsigned long value);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_append_byte (DBusString *str,
unsigned char byte);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_append_printf (DBusString *str,
const char *format,
...) _DBUS_GNUC_PRINTF (2, 3);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_append_printf_valist (DBusString *str,
const char *format,
va_list args);
@@ -170,13 +216,16 @@ dbus_bool_t _dbus_string_insert_8_aligned (DBusString *str,
dbus_bool_t _dbus_string_insert_alignment (DBusString *str,
int *insert_at,
int alignment);
+DBUS_PRIVATE_EXPORT
void _dbus_string_delete (DBusString *str,
int start,
int len);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_move (DBusString *source,
int start,
DBusString *dest,
int insert_at);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_copy (const DBusString *source,
int start,
DBusString *dest,
@@ -186,36 +235,44 @@ dbus_bool_t _dbus_string_move_len (DBusString *source,
int len,
DBusString *dest,
int insert_at);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_copy_len (const DBusString *source,
int start,
int len,
DBusString *dest,
int insert_at);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_replace_len (const DBusString *source,
int start,
int len,
DBusString *dest,
int replace_at,
int replace_len);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_split_on_byte (DBusString *source,
unsigned char byte,
DBusString *tail);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_parse_int (const DBusString *str,
int start,
long *value_return,
int *end_return);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_parse_uint (const DBusString *str,
int start,
unsigned long *value_return,
int *end_return);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_find (const DBusString *str,
int start,
const char *substr,
int *found);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_find_eol (const DBusString *str,
int start,
int *found,
int *found_len);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_find_to (const DBusString *str,
int start,
int end,
@@ -225,62 +282,80 @@ dbus_bool_t _dbus_string_find_byte_backward (const DBusString *str,
int start,
unsigned char byte,
int *found);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_find_blank (const DBusString *str,
int start,
int *found);
+DBUS_PRIVATE_EXPORT
void _dbus_string_skip_blank (const DBusString *str,
int start,
int *end);
+DBUS_PRIVATE_EXPORT
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_PRIVATE_EXPORT
dbus_bool_t _dbus_string_equal (const DBusString *a,
const DBusString *b);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_equal_c_str (const DBusString *a,
const char *c_str);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_equal_len (const DBusString *a,
const DBusString *b,
int len);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_equal_substring (const DBusString *a,
int a_start,
int a_len,
const DBusString *b,
int b_start);
+DBUS_PRIVATE_EXPORT
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_PRIVATE_EXPORT
dbus_bool_t _dbus_string_pop_line (DBusString *source,
DBusString *dest);
+DBUS_PRIVATE_EXPORT
void _dbus_string_delete_first_word (DBusString *str);
+DBUS_PRIVATE_EXPORT
void _dbus_string_delete_leading_blanks (DBusString *str);
+DBUS_PRIVATE_EXPORT
void _dbus_string_chop_white (DBusString *str);
dbus_bool_t _dbus_string_append_byte_as_hex (DBusString *str,
unsigned char byte);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_hex_encode (const DBusString *source,
int start,
DBusString *dest,
int insert_at);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_hex_decode (const DBusString *source,
int start,
int *end_return,
DBusString *dest,
int insert_at);
+DBUS_PRIVATE_EXPORT
void _dbus_string_tolower_ascii (const DBusString *str,
int start,
int len);
+DBUS_PRIVATE_EXPORT
void _dbus_string_toupper_ascii (const DBusString *str,
int start,
int len);
dbus_bool_t _dbus_string_validate_ascii (const DBusString *str,
int start,
int len);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_validate_utf8 (const DBusString *str,
int start,
int len);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_validate_nul (const DBusString *str,
int start,
int len);
diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
index fe891ab7..dc0418cb 100644
--- a/dbus/dbus-sysdeps-unix.c
+++ b/dbus/dbus-sysdeps-unix.c
@@ -29,6 +29,7 @@
#include "dbus-sysdeps-unix.h"
#include "dbus-threads.h"
#include "dbus-protocol.h"
+#include "dbus-file.h"
#include "dbus-transport.h"
#include "dbus-string.h"
#include "dbus-userdb.h"
@@ -53,6 +54,7 @@
#include <sys/stat.h>
#include <sys/wait.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <netdb.h>
#include <grp.h>
#include <arpa/inet.h>
@@ -80,7 +82,9 @@
#include <bsm/adt.h>
#endif
-#include "sd-daemon.h"
+#ifdef HAVE_SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
#if !DBUS_USE_SYNC
#include <pthread.h>
@@ -130,6 +134,9 @@
#endif /* Solaris */
+static dbus_bool_t _dbus_set_fd_nonblocking (int fd,
+ DBusError *error);
+
static dbus_bool_t
_dbus_open_socket (int *fd_p,
int domain,
@@ -198,10 +205,10 @@ _dbus_open_unix_socket (int *fd,
* @returns #FALSE if error is set
*/
dbus_bool_t
-_dbus_close_socket (int fd,
+_dbus_close_socket (DBusSocket fd,
DBusError *error)
{
- return _dbus_close (fd, error);
+ return _dbus_close (fd.fd, error);
}
/**
@@ -214,11 +221,11 @@ _dbus_close_socket (int fd,
* @returns number of bytes appended to the string
*/
int
-_dbus_read_socket (int fd,
+_dbus_read_socket (DBusSocket fd,
DBusString *buffer,
int count)
{
- return _dbus_read (fd, buffer, count);
+ return _dbus_read (fd.fd, buffer, count);
}
/**
@@ -232,7 +239,7 @@ _dbus_read_socket (int fd,
* @returns the number of bytes written or -1 on error
*/
int
-_dbus_write_socket (int fd,
+_dbus_write_socket (DBusSocket fd,
const DBusString *buffer,
int start,
int len)
@@ -245,7 +252,7 @@ _dbus_write_socket (int fd,
again:
- bytes_written = send (fd, data, len, MSG_NOSIGNAL);
+ bytes_written = send (fd.fd, data, len, MSG_NOSIGNAL);
if (bytes_written < 0 && errno == EINTR)
goto again;
@@ -253,7 +260,7 @@ _dbus_write_socket (int fd,
return bytes_written;
#else
- return _dbus_write (fd, buffer, start, len);
+ return _dbus_write (fd.fd, buffer, start, len);
#endif
}
@@ -270,7 +277,7 @@ _dbus_write_socket (int fd,
* @returns number of bytes appended to string
*/
int
-_dbus_read_socket_with_unix_fds (int fd,
+_dbus_read_socket_with_unix_fds (DBusSocket fd,
DBusString *buffer,
int count,
int *fds,
@@ -328,7 +335,7 @@ _dbus_read_socket_with_unix_fds (int fd,
again:
- bytes_read = recvmsg(fd, &m, 0
+ bytes_read = recvmsg (fd.fd, &m, 0
#ifdef MSG_CMSG_CLOEXEC
|MSG_CMSG_CLOEXEC
#endif
@@ -430,7 +437,7 @@ _dbus_read_socket_with_unix_fds (int fd,
}
int
-_dbus_write_socket_with_unix_fds(int fd,
+_dbus_write_socket_with_unix_fds(DBusSocket fd,
const DBusString *buffer,
int start,
int len,
@@ -451,7 +458,7 @@ _dbus_write_socket_with_unix_fds(int fd,
}
int
-_dbus_write_socket_with_unix_fds_two(int fd,
+_dbus_write_socket_with_unix_fds_two(DBusSocket fd,
const DBusString *buffer1,
int start1,
int len1,
@@ -511,7 +518,7 @@ _dbus_write_socket_with_unix_fds_two(int fd,
again:
- bytes_written = sendmsg (fd, &m, 0
+ bytes_written = sendmsg (fd.fd, &m, 0
#if HAVE_DECL_MSG_NOSIGNAL
|MSG_NOSIGNAL
#endif
@@ -543,7 +550,7 @@ _dbus_write_socket_with_unix_fds_two(int fd,
* @returns total bytes written from both buffers, or -1 on error
*/
int
-_dbus_write_socket_two (int fd,
+_dbus_write_socket_two (DBusSocket fd,
const DBusString *buffer1,
int start1,
int len1,
@@ -586,7 +593,7 @@ _dbus_write_socket_two (int fd,
again:
- bytes_written = sendmsg (fd, &m, MSG_NOSIGNAL);
+ bytes_written = sendmsg (fd.fd, &m, MSG_NOSIGNAL);
if (bytes_written < 0 && errno == EINTR)
goto again;
@@ -594,17 +601,11 @@ _dbus_write_socket_two (int fd,
return bytes_written;
#else
- return _dbus_write_two (fd, buffer1, start1, len1,
+ return _dbus_write_two (fd.fd, buffer1, start1, len1,
buffer2, start2, len2);
#endif
}
-dbus_bool_t
-_dbus_socket_is_invalid (int fd)
-{
- return fd < 0 ? TRUE : FALSE;
-}
-
/**
* Thin wrapper around the read() system call that appends
* the data it reads to the DBusString buffer. It appends
@@ -1102,7 +1103,7 @@ _dbus_listen_unix_socket (const char *path,
if (path_len > _DBUS_MAX_SUN_PATH_LENGTH)
{
dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
- "Abstract socket name too long\n");
+ "Socket name too long\n");
_dbus_close (listen_fd, NULL);
return -1;
}
@@ -1156,12 +1157,13 @@ _dbus_listen_unix_socket (const char *path,
* @returns the number of file descriptors
*/
int
-_dbus_listen_systemd_sockets (int **fds,
- DBusError *error)
+_dbus_listen_systemd_sockets (DBusSocket **fds,
+ DBusError *error)
{
+#ifdef HAVE_SYSTEMD
int r, n;
- unsigned fd;
- int *new_fds;
+ int fd;
+ DBusSocket *new_fds;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -1203,7 +1205,7 @@ _dbus_listen_systemd_sockets (int **fds,
/* OK, the file descriptors are all good, so let's take posession of
them then. */
- new_fds = dbus_new (int, n);
+ new_fds = dbus_new (DBusSocket, n);
if (!new_fds)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
@@ -1219,7 +1221,7 @@ _dbus_listen_systemd_sockets (int **fds,
goto fail;
}
- new_fds[fd - SD_LISTEN_FDS_START] = fd;
+ new_fds[fd - SD_LISTEN_FDS_START].fd = fd;
}
*fds = new_fds;
@@ -1234,6 +1236,11 @@ _dbus_listen_systemd_sockets (int **fds,
dbus_free (new_fds);
return -1;
+#else
+ dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+ "dbus was compiled without systemd support");
+ return -1;
+#endif
}
/**
@@ -1249,7 +1256,7 @@ _dbus_listen_systemd_sockets (int **fds,
* @param error return location for error code
* @returns connection file descriptor or -1 on error
*/
-int
+DBusSocket
_dbus_connect_tcp_socket (const char *host,
const char *port,
const char *family,
@@ -1258,7 +1265,7 @@ _dbus_connect_tcp_socket (const char *host,
return _dbus_connect_tcp_socket_with_nonce (host, port, family, (const char*)NULL, error);
}
-int
+DBusSocket
_dbus_connect_tcp_socket_with_nonce (const char *host,
const char *port,
const char *family,
@@ -1266,7 +1273,8 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
DBusError *error)
{
int saved_errno = 0;
- int fd = -1, res;
+ DBusSocket fd = DBUS_SOCKET_INIT;
+ int res;
struct addrinfo hints;
struct addrinfo *ai, *tmp;
@@ -1285,7 +1293,7 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
dbus_set_error (error,
DBUS_ERROR_BAD_ADDRESS,
"Unknown address family %s", family);
- return -1;
+ return _dbus_socket_get_invalid ();
}
hints.ai_protocol = IPPROTO_TCP;
hints.ai_socktype = SOCK_STREAM;
@@ -1297,25 +1305,25 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
_dbus_error_from_errno (errno),
"Failed to lookup host/port: \"%s:%s\": %s (%d)",
host, port, gai_strerror(res), res);
- return -1;
+ return _dbus_socket_get_invalid ();
}
tmp = ai;
while (tmp)
{
- if (!_dbus_open_socket (&fd, tmp->ai_family, SOCK_STREAM, 0, error))
+ if (!_dbus_open_socket (&fd.fd, tmp->ai_family, SOCK_STREAM, 0, error))
{
freeaddrinfo(ai);
_DBUS_ASSERT_ERROR_IS_SET(error);
- return -1;
+ return _dbus_socket_get_invalid ();
}
_DBUS_ASSERT_ERROR_IS_CLEAR(error);
- if (connect (fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) < 0)
+ if (connect (fd.fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) < 0)
{
saved_errno = errno;
- _dbus_close(fd, NULL);
- fd = -1;
+ _dbus_close (fd.fd, NULL);
+ fd.fd = -1;
tmp = tmp->ai_next;
continue;
}
@@ -1324,13 +1332,13 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
}
freeaddrinfo(ai);
- if (fd == -1)
+ if (fd.fd == -1)
{
dbus_set_error (error,
_dbus_error_from_errno (saved_errno),
"Failed to connect to socket \"%s:%s\" %s",
host, port, _dbus_strerror(saved_errno));
- return -1;
+ return _dbus_socket_get_invalid ();
}
if (noncefile != NULL)
@@ -1342,16 +1350,16 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
_dbus_string_free (&noncefileStr);
if (!ret)
- {
- _dbus_close (fd, NULL);
- return -1;
+ {
+ _dbus_close (fd.fd, NULL);
+ return _dbus_socket_get_invalid ();
}
}
- if (!_dbus_set_fd_nonblocking (fd, error))
+ if (!_dbus_set_fd_nonblocking (fd.fd, error))
{
- _dbus_close (fd, NULL);
- return -1;
+ _dbus_close (fd.fd, NULL);
+ return _dbus_socket_get_invalid ();
}
return fd;
@@ -1378,11 +1386,12 @@ _dbus_listen_tcp_socket (const char *host,
const char *port,
const char *family,
DBusString *retport,
- int **fds_p,
+ DBusSocket **fds_p,
DBusError *error)
{
int saved_errno;
- int nlisten_fd = 0, *listen_fd = NULL, res, i;
+ int nlisten_fd = 0, res, i;
+ DBusSocket *listen_fd = NULL;
struct addrinfo hints;
struct addrinfo *ai, *tmp;
unsigned int reuseaddr;
@@ -1424,7 +1433,9 @@ _dbus_listen_tcp_socket (const char *host,
tmp = ai;
while (tmp)
{
- int fd = -1, *newlisten_fd;
+ int fd = -1, tcp_nodelay_on;
+ DBusSocket *newlisten_fd;
+
if (!_dbus_open_socket (&fd, tmp->ai_family, SOCK_STREAM, 0, error))
{
_DBUS_ASSERT_ERROR_IS_SET(error);
@@ -1439,15 +1450,33 @@ _dbus_listen_tcp_socket (const char *host,
host ? host : "*", port, _dbus_strerror (errno));
}
+ /* Nagle's algorithm imposes a huge delay on the initial messages
+ going over TCP. */
+ tcp_nodelay_on = 1;
+ if (setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &tcp_nodelay_on, sizeof (tcp_nodelay_on)) == -1)
+ {
+ _dbus_warn ("Failed to set TCP_NODELAY socket option \"%s:%s\": %s",
+ host ? host : "*", port, _dbus_strerror (errno));
+ }
+
if (bind (fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) < 0)
{
saved_errno = errno;
_dbus_close(fd, NULL);
if (saved_errno == EADDRINUSE)
{
- /* Depending on kernel policy, it may or may not
- be neccessary to bind to both IPv4 & 6 addresses
- so ignore EADDRINUSE here */
+ /* Depending on kernel policy, binding to an IPv6 address
+ might implicitly bind to a corresponding IPv4
+ address or vice versa, resulting in EADDRINUSE for the
+ other one (e.g. bindv6only=0 on Linux).
+
+ Also, after we "goto redo_lookup_with_port" after binding
+ a port on one of the possible addresses, we will
+ try to bind that same port on every address, including the
+ same address again for a second time; that one will
+ also fail with EADDRINUSE.
+
+ For both those reasons, ignore EADDRINUSE here */
tmp = tmp->ai_next;
continue;
}
@@ -1467,7 +1496,7 @@ _dbus_listen_tcp_socket (const char *host,
goto failed;
}
- newlisten_fd = dbus_realloc(listen_fd, sizeof(int)*(nlisten_fd+1));
+ newlisten_fd = dbus_realloc(listen_fd, sizeof(DBusSocket)*(nlisten_fd+1));
if (!newlisten_fd)
{
saved_errno = errno;
@@ -1478,7 +1507,7 @@ _dbus_listen_tcp_socket (const char *host,
goto failed;
}
listen_fd = newlisten_fd;
- listen_fd[nlisten_fd] = fd;
+ listen_fd[nlisten_fd].fd = fd;
nlisten_fd++;
if (!_dbus_string_get_length(retport))
@@ -1500,7 +1529,7 @@ _dbus_listen_tcp_socket (const char *host,
if (result == -1 ||
(res = getnameinfo ((struct sockaddr*)&addr, addrlen, NULL, 0,
portbuf, sizeof(portbuf),
- NI_NUMERICHOST)) != 0)
+ NI_NUMERICHOST | NI_NUMERICSERV)) != 0)
{
dbus_set_error (error, _dbus_error_from_errno (errno),
"Failed to resolve port \"%s:%s\": %s (%s)",
@@ -1544,7 +1573,7 @@ _dbus_listen_tcp_socket (const char *host,
for (i = 0 ; i < nlisten_fd ; i++)
{
- if (!_dbus_set_fd_nonblocking (listen_fd[i], error))
+ if (!_dbus_set_fd_nonblocking (listen_fd[i].fd, error))
{
goto failed;
}
@@ -1558,7 +1587,7 @@ _dbus_listen_tcp_socket (const char *host,
if (ai)
freeaddrinfo(ai);
for (i = 0 ; i < nlisten_fd ; i++)
- _dbus_close(listen_fd[i], NULL);
+ _dbus_close(listen_fd[i].fd, NULL);
dbus_free(listen_fd);
return -1;
}
@@ -1639,12 +1668,130 @@ write_credentials_byte (int server_fd,
}
}
+/* return FALSE on OOM, TRUE otherwise, even if no credentials were found */
+static dbus_bool_t
+add_linux_security_label_to_credentials (int client_fd,
+ DBusCredentials *credentials)
+{
+#if defined(__linux__) && defined(SO_PEERSEC)
+ DBusString buf;
+ socklen_t len = 1024;
+ dbus_bool_t oom = FALSE;
+
+ if (!_dbus_string_init_preallocated (&buf, len) ||
+ !_dbus_string_set_length (&buf, len))
+ return FALSE;
+
+ while (getsockopt (client_fd, SOL_SOCKET, SO_PEERSEC,
+ _dbus_string_get_data (&buf), &len) < 0)
+ {
+ int e = errno;
+
+ _dbus_verbose ("getsockopt failed with %s, len now %lu\n",
+ _dbus_strerror (e), (unsigned long) len);
+
+ if (e != ERANGE || len <= _dbus_string_get_length_uint (&buf))
+ {
+ _dbus_verbose ("Failed to getsockopt(SO_PEERSEC): %s\n",
+ _dbus_strerror (e));
+ goto out;
+ }
+
+ /* If not enough space, len is updated to be enough.
+ * Try again with a large enough buffer. */
+ if (!_dbus_string_set_length (&buf, len))
+ {
+ oom = TRUE;
+ goto out;
+ }
+
+ _dbus_verbose ("will try again with %lu\n", (unsigned long) len);
+ }
+
+ if (len <= 0)
+ {
+ _dbus_verbose ("getsockopt(SO_PEERSEC) yielded <= 0 bytes: %lu\n",
+ (unsigned long) len);
+ goto out;
+ }
+
+ if (len > _dbus_string_get_length_uint (&buf))
+ {
+ _dbus_verbose ("%lu > %u", (unsigned long) len,
+ _dbus_string_get_length_uint (&buf));
+ _dbus_assert_not_reached ("getsockopt(SO_PEERSEC) overflowed");
+ }
+
+ if (_dbus_string_get_byte (&buf, len - 1) == 0)
+ {
+ /* the kernel included the trailing \0 in its count,
+ * but DBusString always has an extra \0 after the data anyway */
+ _dbus_verbose ("subtracting trailing \\0\n");
+ len--;
+ }
+
+ if (!_dbus_string_set_length (&buf, len))
+ {
+ _dbus_assert_not_reached ("shortening string should not lead to OOM");
+ oom = TRUE;
+ goto out;
+ }
+
+ if (strlen (_dbus_string_get_const_data (&buf)) != len)
+ {
+ /* LSM people on the linux-security-module@ mailing list say this
+ * should never happen: the label should be a bytestring with
+ * an optional trailing \0 */
+ _dbus_verbose ("security label from kernel had an embedded \\0, "
+ "ignoring it\n");
+ goto out;
+ }
+
+ _dbus_verbose ("getsockopt(SO_PEERSEC): %lu bytes excluding \\0: %s\n",
+ (unsigned long) len,
+ _dbus_string_get_const_data (&buf));
+
+ if (!_dbus_credentials_add_linux_security_label (credentials,
+ _dbus_string_get_const_data (&buf)))
+ {
+ oom = TRUE;
+ goto out;
+ }
+
+out:
+ _dbus_string_free (&buf);
+ return !oom;
+#else
+ /* no error */
+ return TRUE;
+#endif
+}
+
/**
* 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.
*
+ * DBusServer makes the security assumption that the credentials
+ * returned by this method are the credentials that were active
+ * at the time the socket was opened. Do not add APIs to this
+ * method that would break that assumption.
+ *
+ * In particular, it is incorrect to use any API of the form
+ * "get the process ID at the other end of the connection, then
+ * determine its uid, gid, or other credentials from the pid"
+ * (e.g. looking in /proc on Linux). If we did that, we would
+ * be vulnerable to several attacks. A malicious process could
+ * queue up the rest of the authentication handshake and a malicious
+ * message that it should not be allowed to send, then race with
+ * the DBusServer to exec() a more privileged (e.g. setuid) binary that
+ * would have been allowed to send that message; or it could exit,
+ * and arrange for enough setuid processes to be started that its
+ * pid would be recycled for one of those processes with high
+ * probability; or it could fd-pass the connection to a more
+ * privileged process.
+ *
* 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
@@ -1661,7 +1808,7 @@ write_credentials_byte (int server_fd,
* @returns #TRUE on success
*/
dbus_bool_t
-_dbus_read_credentials_socket (int client_fd,
+_dbus_read_credentials_socket (DBusSocket client_fd,
DBusCredentials *credentials,
DBusError *error)
{
@@ -1679,18 +1826,18 @@ _dbus_read_credentials_socket (int client_fd,
} 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_STATIC_ASSERT (sizeof (pid_t) <= sizeof (dbus_pid_t));
+ _DBUS_STATIC_ASSERT (sizeof (uid_t) <= sizeof (dbus_uid_t));
+ _DBUS_STATIC_ASSERT (sizeof (gid_t) <= sizeof (dbus_gid_t));
+
+ uid_read = DBUS_UID_UNSET;
+ pid_read = DBUS_PID_UNSET;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
_dbus_credentials_clear (credentials);
@@ -1708,7 +1855,7 @@ _dbus_read_credentials_socket (int client_fd,
#endif
again:
- bytes_read = recvmsg (client_fd, &msg, 0);
+ bytes_read = recvmsg (client_fd.fd, &msg, 0);
if (bytes_read < 0)
{
@@ -1760,16 +1907,41 @@ _dbus_read_credentials_socket (int client_fd,
#endif
int cr_len = sizeof (cr);
- if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&
- cr_len == sizeof (cr))
+ if (getsockopt (client_fd.fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) != 0)
+ {
+ _dbus_verbose ("Failed to getsockopt(SO_PEERCRED): %s\n",
+ _dbus_strerror (errno));
+ }
+ else if (cr_len != sizeof (cr))
+ {
+ _dbus_verbose ("Failed to getsockopt(SO_PEERCRED), returned %d bytes, expected %d\n",
+ cr_len, (int) sizeof (cr));
+ }
+ else
+ {
+ pid_read = cr.pid;
+ uid_read = cr.uid;
+ }
+#elif defined(HAVE_UNPCBID) && defined(LOCAL_PEEREID)
+ /* Another variant of the above - used on NetBSD
+ */
+ struct unpcbid cr;
+ socklen_t cr_len = sizeof (cr);
+
+ if (getsockopt (client_fd.fd, 0, LOCAL_PEEREID, &cr, &cr_len) != 0)
+ {
+ _dbus_verbose ("Failed to getsockopt(LOCAL_PEEREID): %s\n",
+ _dbus_strerror (errno));
+ }
+ else if (cr_len != sizeof (cr))
{
- pid_read = cr.pid;
- uid_read = cr.uid;
+ _dbus_verbose ("Failed to getsockopt(LOCAL_PEEREID), returned %d bytes, expected %d\n",
+ cr_len, (int) sizeof (cr));
}
else
{
- _dbus_verbose ("Failed to getsockopt() credentials, returned len %d/%d: %s\n",
- cr_len, (int) sizeof (cr), _dbus_strerror (errno));
+ pid_read = cr.unp_pid;
+ uid_read = cr.unp_euid;
}
#elif defined(HAVE_CMSGCRED)
/* We only check for HAVE_CMSGCRED, but we're really assuming that the
@@ -1803,7 +1975,7 @@ _dbus_read_credentials_socket (int client_fd,
* up this list, because it carries the pid and we use this code path
* for audit data. */
ucred_t * ucred = NULL;
- if (getpeerucred (client_fd, &ucred) == 0)
+ if (getpeerucred (client_fd.fd, &ucred) == 0)
{
pid_read = ucred_getpid (ucred);
uid_read = ucred_geteuid (ucred);
@@ -1869,7 +2041,7 @@ _dbus_read_credentials_socket (int client_fd,
*/
uid_t euid;
gid_t egid;
- if (getpeereid (client_fd, &euid, &egid) == 0)
+ if (getpeereid (client_fd.fd, &euid, &egid) == 0)
{
uid_read = euid;
}
@@ -1922,6 +2094,12 @@ _dbus_read_credentials_socket (int client_fd,
}
}
+ if (!add_linux_security_label_to_credentials (client_fd.fd, credentials))
+ {
+ _DBUS_SET_OOM (error);
+ return FALSE;
+ }
+
return TRUE;
}
@@ -1943,12 +2121,12 @@ _dbus_read_credentials_socket (int client_fd,
* @returns #TRUE if the byte was sent
*/
dbus_bool_t
-_dbus_send_credentials_socket (int server_fd,
+_dbus_send_credentials_socket (DBusSocket server_fd,
DBusError *error)
{
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
- if (write_credentials_byte (server_fd, error))
+ if (write_credentials_byte (server_fd.fd, error))
return TRUE;
else
return FALSE;
@@ -1963,10 +2141,10 @@ _dbus_send_credentials_socket (int server_fd,
* @param listen_fd the listen file descriptor
* @returns the connection fd of the client, or -1 on error
*/
-int
-_dbus_accept (int listen_fd)
+DBusSocket
+_dbus_accept (DBusSocket listen_fd)
{
- int client_fd;
+ DBusSocket client_fd;
struct sockaddr addr;
socklen_t addrlen;
#ifdef HAVE_ACCEPT4
@@ -1983,28 +2161,28 @@ _dbus_accept (int listen_fd)
* libc headers, SOCK_CLOEXEC is too. At runtime, it is still
* not necessarily true that either is supported by the running kernel.
*/
- client_fd = accept4 (listen_fd, &addr, &addrlen, SOCK_CLOEXEC);
- cloexec_done = client_fd >= 0;
+ client_fd.fd = accept4 (listen_fd.fd, &addr, &addrlen, SOCK_CLOEXEC);
+ cloexec_done = client_fd.fd >= 0;
- if (client_fd < 0 && (errno == ENOSYS || errno == EINVAL))
+ if (client_fd.fd < 0 && (errno == ENOSYS || errno == EINVAL))
#endif
{
- client_fd = accept (listen_fd, &addr, &addrlen);
+ client_fd.fd = accept (listen_fd.fd, &addr, &addrlen);
}
- if (client_fd < 0)
+ if (client_fd.fd < 0)
{
if (errno == EINTR)
goto retry;
}
- _dbus_verbose ("client fd %d accepted\n", client_fd);
+ _dbus_verbose ("client fd %d accepted\n", client_fd.fd);
#ifdef HAVE_ACCEPT4
if (!cloexec_done)
#endif
{
- _dbus_fd_set_close_on_exec(client_fd);
+ _dbus_fd_set_close_on_exec(client_fd.fd);
}
return client_fd;
@@ -2371,9 +2549,9 @@ _dbus_credentials_add_from_current_process (DBusCredentials *credentials)
* 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_STATIC_ASSERT (sizeof (pid_t) <= sizeof (dbus_pid_t));
+ _DBUS_STATIC_ASSERT (sizeof (uid_t) <= sizeof (dbus_uid_t));
+ _DBUS_STATIC_ASSERT (sizeof (gid_t) <= sizeof (dbus_gid_t));
if (!_dbus_credentials_add_pid(credentials, _dbus_getpid()))
return FALSE;
@@ -2592,6 +2770,11 @@ _dbus_poll (DBusPollFD *fds,
_DBUS_STRUCT_OFFSET (DBusPollFD, revents) ==
_DBUS_STRUCT_OFFSET (struct pollfd, revents))
{
+ if (timeout_milliseconds < -1)
+ {
+ timeout_milliseconds = -1;
+ }
+
return poll ((struct pollfd*) fds,
n_fds,
timeout_milliseconds);
@@ -2820,61 +3003,55 @@ _dbus_sleep_milliseconds (int milliseconds)
#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,
+ * Generates the given number of securely 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
+ * @param error location to store reason for failure
+ * @returns #TRUE on success, #FALSE on error
*/
dbus_bool_t
_dbus_generate_random_bytes (DBusString *str,
- int n_bytes)
+ int n_bytes,
+ DBusError *error)
{
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.
- */
+ int result;
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_set_error (error, _dbus_error_from_errno (errno),
+ "Could not open /dev/urandom: %s",
+ _dbus_strerror (errno));
+ return FALSE;
+ }
_dbus_verbose ("/dev/urandom fd %d opened\n", fd);
- if (_dbus_read (fd, str, n_bytes) != n_bytes)
+ result = _dbus_read (fd, str, n_bytes);
+
+ if (result != n_bytes)
{
+ if (result < 0)
+ dbus_set_error (error, _dbus_error_from_errno (errno),
+ "Could not read /dev/urandom: %s",
+ _dbus_strerror (errno));
+ else
+ dbus_set_error (error, DBUS_ERROR_IO_ERROR,
+ "Short read from /dev/urandom");
+
_dbus_close (fd, NULL);
_dbus_string_set_length (str, old_len);
- return _dbus_generate_pseudorandom_bytes (str, n_bytes);
+ return FALSE;
}
_dbus_verbose ("Read %d bytes from /dev/urandom\n",
@@ -2933,7 +3110,7 @@ _dbus_disable_sigpipe (void)
* @param fd the file descriptor
*/
void
-_dbus_fd_set_close_on_exec (intptr_t fd)
+_dbus_fd_set_close_on_exec (int fd)
{
int val;
@@ -3025,6 +3202,13 @@ _dbus_dup(int fd,
* @returns #TRUE on success.
*/
dbus_bool_t
+_dbus_set_socket_nonblocking (DBusSocket fd,
+ DBusError *error)
+{
+ return _dbus_set_fd_nonblocking (fd.fd, error);
+}
+
+static dbus_bool_t
_dbus_set_fd_nonblocking (int fd,
DBusError *error)
{
@@ -3093,22 +3277,22 @@ _dbus_print_backtrace (void)
}
/**
- * Creates a full-duplex pipe (as in socketpair()).
- * Sets both ends of the pipe nonblocking.
+ * Creates pair of connect sockets (as in socketpair()).
+ * Sets both ends of the pair nonblocking.
*
* Marks both file descriptors as close-on-exec
*
* @param fd1 return location for one end
* @param fd2 return location for the other end
- * @param blocking #TRUE if pipe should be blocking
+ * @param blocking #TRUE if pair 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)
+_dbus_socketpair (DBusSocket *fd1,
+ DBusSocket *fd2,
+ dbus_bool_t blocking,
+ DBusError *error)
{
#ifdef HAVE_SOCKETPAIR
int fds[2];
@@ -3156,17 +3340,17 @@ _dbus_full_duplex_pipe (int *fd1,
return FALSE;
}
- *fd1 = fds[0];
- *fd2 = fds[1];
+ fd1->fd = fds[0];
+ fd2->fd = fds[1];
_dbus_verbose ("full-duplex pipe %d <-> %d\n",
- *fd1, *fd2);
+ fd1->fd, fd2->fd);
return TRUE;
#else
- _dbus_warn ("_dbus_full_duplex_pipe() not implemented on this OS\n");
+ _dbus_warn ("_dbus_socketpair() not implemented on this OS\n");
dbus_set_error (error, DBUS_ERROR_FAILED,
- "_dbus_full_duplex_pipe() not implemented on this OS");
+ "_dbus_socketpair() not implemented on this OS");
return FALSE;
#endif
}
@@ -3513,6 +3697,7 @@ _dbus_get_autolaunch_address (const char *scope,
* but that's done elsewhere, and if it worked, this function wouldn't
* be called.) */
const char *display;
+ char *progpath;
char *argv[6];
int i;
DBusString uuid;
@@ -3530,7 +3715,12 @@ _dbus_get_autolaunch_address (const char *scope,
/* fd.o #19997: if $DISPLAY isn't set to something useful, then
* dbus-launch-x11 is just going to fail. Rather than trying to
- * run it, we might as well bail out early with a nice error. */
+ * run it, we might as well bail out early with a nice error.
+ *
+ * This is not strictly true in a world where the user bus exists,
+ * because dbus-launch --autolaunch knows how to connect to that -
+ * but if we were going to connect to the user bus, we'd have done
+ * so before trying autolaunch: in any case. */
display = _dbus_getenv ("DISPLAY");
if (display == NULL || display[0] == '\0')
@@ -3546,19 +3736,24 @@ _dbus_get_autolaunch_address (const char *scope,
return FALSE;
}
- if (!_dbus_get_local_machine_uuid_encoded (&uuid))
+ if (!_dbus_get_local_machine_uuid_encoded (&uuid, error))
{
- _DBUS_SET_OOM (error);
goto out;
}
- i = 0;
#ifdef DBUS_ENABLE_EMBEDDED_TESTS
if (_dbus_getenv ("DBUS_USE_TEST_BINARY") != NULL)
- argv[i] = TEST_BUS_LAUNCH_BINARY;
+ progpath = TEST_BUS_LAUNCH_BINARY;
else
#endif
- argv[i] = DBUS_BINDIR "/dbus-launch";
+ progpath = DBUS_BINDIR "/dbus-launch";
+ /*
+ * argv[0] is always dbus-launch, that's the name what we'll
+ * get from /proc, or ps(1), regardless what the progpath is,
+ * see fd.o#69716
+ */
+ i = 0;
+ argv[i] = "dbus-launch";
++i;
argv[i] = "--autolaunch";
++i;
@@ -3573,7 +3768,7 @@ _dbus_get_autolaunch_address (const char *scope,
_dbus_assert (i == _DBUS_N_ELEMENTS (argv));
- retval = _read_subprocess_line_argv (argv[0],
+ retval = _read_subprocess_line_argv (progpath,
TRUE,
argv, address, error);
@@ -3642,7 +3837,10 @@ _dbus_read_local_machine_uuid (DBusGUID *machine_id,
/* if none found, try to make a new one */
dbus_error_free (error);
_dbus_string_init_const (&filename, DBUS_MACHINE_UUID_FILE);
- _dbus_generate_uuid (machine_id);
+
+ if (!_dbus_generate_uuid (machine_id, error))
+ return FALSE;
+
return _dbus_write_uuid_file (&filename, machine_id, error);
}
@@ -3759,6 +3957,77 @@ _dbus_lookup_session_address_launchd (DBusString *address, DBusError *error)
}
#endif
+dbus_bool_t
+_dbus_lookup_user_bus (dbus_bool_t *supported,
+ DBusString *address,
+ DBusError *error)
+{
+ const char *runtime_dir = _dbus_getenv ("XDG_RUNTIME_DIR");
+ dbus_bool_t ret = FALSE;
+ struct stat stbuf;
+ DBusString user_bus_path;
+
+ if (runtime_dir == NULL)
+ {
+ _dbus_verbose ("XDG_RUNTIME_DIR not found in environment");
+ *supported = FALSE;
+ return TRUE; /* Cannot use it, but not an error */
+ }
+
+ if (!_dbus_string_init (&user_bus_path))
+ {
+ _DBUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!_dbus_string_append_printf (&user_bus_path, "%s/bus", runtime_dir))
+ {
+ _DBUS_SET_OOM (error);
+ goto out;
+ }
+
+ if (lstat (_dbus_string_get_const_data (&user_bus_path), &stbuf) == -1)
+ {
+ _dbus_verbose ("XDG_RUNTIME_DIR/bus not available: %s",
+ _dbus_strerror (errno));
+ *supported = FALSE;
+ ret = TRUE; /* Cannot use it, but not an error */
+ goto out;
+ }
+
+ if (stbuf.st_uid != getuid ())
+ {
+ _dbus_verbose ("XDG_RUNTIME_DIR/bus owned by uid %ld, not our uid %ld",
+ (long) stbuf.st_uid, (long) getuid ());
+ *supported = FALSE;
+ ret = TRUE; /* Cannot use it, but not an error */
+ goto out;
+ }
+
+ if ((stbuf.st_mode & S_IFMT) != S_IFSOCK)
+ {
+ _dbus_verbose ("XDG_RUNTIME_DIR/bus is not a socket: st_mode = 0o%lo",
+ (long) stbuf.st_mode);
+ *supported = FALSE;
+ ret = TRUE; /* Cannot use it, but not an error */
+ goto out;
+ }
+
+ if (!_dbus_string_append (address, "unix:path=") ||
+ !_dbus_address_append_escaped (address, &user_bus_path))
+ {
+ _DBUS_SET_OOM (error);
+ goto out;
+ }
+
+ *supported = TRUE;
+ ret = TRUE;
+
+out:
+ _dbus_string_free (&user_bus_path);
+ return ret;
+}
+
/**
* Determines the address of the session bus by querying a
* platform-specific method.
@@ -3787,11 +4056,18 @@ _dbus_lookup_session_address (dbus_bool_t *supported,
*supported = TRUE;
return _dbus_lookup_session_address_launchd (address, error);
#else
- /* 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;
+
+ if (!_dbus_lookup_user_bus (supported, address, error))
+ return FALSE;
+ else if (*supported)
+ return TRUE;
+
+ /* On non-Mac Unix platforms, if the session address isn't already
+ * set in DBUS_SESSION_BUS_ADDRESS environment variable and the
+ * $XDG_RUNTIME_DIR/bus can't be used, we punt and fall back to the
+ * autolaunch: global default; see init_session_address in
+ * dbus/dbus-bus.c. */
return TRUE;
#endif
}
@@ -3907,12 +4183,12 @@ _dbus_daemon_unpublish_session_bus_address (void)
* 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
+ * @returns #TRUE if e == EAGAIN or e == EWOULDBLOCK
*/
dbus_bool_t
-_dbus_get_is_errno_eagain_or_ewouldblock (void)
+_dbus_get_is_errno_eagain_or_ewouldblock (int e)
{
- return errno == EAGAIN || errno == EWOULDBLOCK;
+ return e == EAGAIN || e == EWOULDBLOCK;
}
/**
@@ -3951,8 +4227,8 @@ _dbus_delete_directory (const DBusString *filename,
*
*/
dbus_bool_t
-_dbus_socket_can_pass_unix_fd(int fd) {
-
+_dbus_socket_can_pass_unix_fd (DBusSocket fd)
+{
#ifdef SCM_RIGHTS
union {
struct sockaddr sa;
@@ -3964,7 +4240,7 @@ _dbus_socket_can_pass_unix_fd(int fd) {
_DBUS_ZERO(sa_buf);
- if (getsockname(fd, &sa_buf.sa, &sa_len) < 0)
+ if (getsockname(fd.fd, &sa_buf.sa, &sa_len) < 0)
return FALSE;
return sa_buf.sa.sa_family == AF_UNIX;
@@ -4103,7 +4379,7 @@ _dbus_check_setuid (void)
* @param error return location for error code
*/
dbus_bool_t
-_dbus_append_address_from_socket (int fd,
+_dbus_append_address_from_socket (DBusSocket fd,
DBusString *address,
DBusError *error)
{
@@ -4118,7 +4394,7 @@ _dbus_append_address_from_socket (int fd,
int size = sizeof (socket);
DBusString path_str;
- if (getsockname (fd, &socket.sa, &size))
+ if (getsockname (fd.fd, &socket.sa, &size))
goto err;
switch (socket.sa.sa_family)
@@ -4169,4 +4445,16 @@ _dbus_append_address_from_socket (int fd,
return FALSE;
}
+int
+_dbus_save_socket_errno (void)
+{
+ return errno;
+}
+
+void
+_dbus_restore_socket_errno (int saved_errno)
+{
+ errno = saved_errno;
+}
+
/* tests in dbus-sysdeps-util.c */
diff --git a/dbus/dbus-sysdeps-unix.h b/dbus/dbus-sysdeps-unix.h
index a265b335..0932129f 100644
--- a/dbus/dbus-sysdeps-unix.h
+++ b/dbus/dbus-sysdeps-unix.h
@@ -40,11 +40,14 @@ DBUS_BEGIN_DECLS
* @{
*/
+DBUS_PRIVATE_EXPORT
dbus_bool_t
_dbus_close (int fd,
DBusError *error);
+DBUS_PRIVATE_EXPORT
int _dbus_dup (int fd,
DBusError *error);
+DBUS_PRIVATE_EXPORT
int
_dbus_read (int fd,
DBusString *buffer,
@@ -74,8 +77,8 @@ int _dbus_connect_exec (const char *path,
char *const argv[],
DBusError *error);
-int _dbus_listen_systemd_sockets (int **fd,
- DBusError *error);
+int _dbus_listen_systemd_sockets (DBusSocket **fd,
+ DBusError *error);
dbus_bool_t _dbus_read_credentials (int client_fd,
DBusCredentials *credentials,
@@ -87,6 +90,11 @@ dbus_bool_t _dbus_lookup_launchd_socket (DBusString *socket_path,
const char *launchd_env_var,
DBusError *error);
+DBUS_PRIVATE_EXPORT
+dbus_bool_t _dbus_lookup_user_bus (dbus_bool_t *supported,
+ DBusString *address,
+ DBusError *error);
+
/** Information about a UNIX user */
typedef struct DBusUserInfo DBusUserInfo;
/** Information about a UNIX group */
@@ -131,17 +139,22 @@ dbus_bool_t _dbus_group_info_fill_gid (DBusGroupInfo *info,
void _dbus_group_info_free (DBusGroupInfo *info);
dbus_uid_t _dbus_getuid (void);
+DBUS_PRIVATE_EXPORT
dbus_uid_t _dbus_geteuid (void);
dbus_bool_t _dbus_parse_uid (const DBusString *uid_str,
dbus_uid_t *uid);
+DBUS_PRIVATE_EXPORT
void _dbus_close_all (void);
-dbus_bool_t _dbus_append_address_from_socket (int fd,
+dbus_bool_t _dbus_append_address_from_socket (DBusSocket fd,
DBusString *address,
DBusError *error);
+DBUS_PRIVATE_EXPORT
+void _dbus_fd_set_close_on_exec (int fd);
+
/** @} */
DBUS_END_DECLS
diff --git a/dbus/dbus-sysdeps-util-unix.c b/dbus/dbus-sysdeps-util-unix.c
index 199eb3dd..9b724cc9 100644
--- a/dbus/dbus-sysdeps-util-unix.c
+++ b/dbus/dbus-sysdeps-util-unix.c
@@ -58,7 +58,9 @@
#include <sys/syslimits.h>
#endif
-#include "sd-daemon.h"
+#ifdef HAVE_SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
#ifndef O_BINARY
#define O_BINARY 0
@@ -570,6 +572,9 @@ _dbus_system_logv (DBusSystemLogSeverity severity, const char *msg, va_list args
case DBUS_SYSTEM_LOG_INFO:
flags = LOG_DAEMON | LOG_NOTICE;
break;
+ case DBUS_SYSTEM_LOG_WARNING:
+ flags = LOG_DAEMON | LOG_WARNING;
+ break;
case DBUS_SYSTEM_LOG_SECURITY:
flags = LOG_AUTH | LOG_NOTICE;
break;
diff --git a/dbus/dbus-sysdeps-util-win.c b/dbus/dbus-sysdeps-util-win.c
index ec9afbb6..e83c5397 100644
--- a/dbus/dbus-sysdeps-util-win.c
+++ b/dbus/dbus-sysdeps-util-win.c
@@ -339,6 +339,7 @@ _dbus_system_logv (DBusSystemLogSeverity severity, const char *msg, va_list args
switch(severity)
{
case DBUS_SYSTEM_LOG_INFO: s = "info"; break;
+ case DBUS_SYSTEM_LOG_WARNING: s = "warning"; break;
case DBUS_SYSTEM_LOG_SECURITY: s = "security"; break;
case DBUS_SYSTEM_LOG_FATAL: s = "fatal"; break;
}
@@ -379,7 +380,6 @@ _dbus_stat(const DBusString *filename,
const char *filename_c;
WIN32_FILE_ATTRIBUTE_DATA wfad;
char *lastdot;
- DWORD rc;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -457,155 +457,15 @@ _dbus_stat(const DBusString *filename,
return TRUE;
}
-
-/* This file is part of the KDE project
-Copyright (C) 2000 Werner Almesberger
-
-libc/sys/linux/sys/dirent.h - Directory entry as returned by readdir
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library 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
-Library General Public License for more details.
-
-You should have received a copy of the GNU Library General Public License
-along with this program; see the file COPYING. If not, write to
-the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.
-*/
-#define HAVE_NO_D_NAMLEN /* no struct dirent->d_namlen */
-#define HAVE_DD_LOCK /* have locking mechanism */
-
-#define MAXNAMLEN 255 /* sizeof(struct dirent.d_name)-1 */
-
-#define __dirfd(dir) (dir)->dd_fd
-
-/* struct dirent - same as Unix */
-struct dirent
- {
- long d_ino; /* inode (always 1 in WIN32) */
- off_t d_off; /* offset to this dirent */
- unsigned short d_reclen; /* length of d_name */
- char d_name[_MAX_FNAME+1]; /* filename (null terminated) */
- };
-
-/* typedef DIR - not the same as Unix */
-typedef struct
- {
- HANDLE handle; /* FindFirst/FindNext handle */
- short offset; /* offset into directory */
- short finished; /* 1 if there are not more files */
- WIN32_FIND_DATAA fileinfo; /* from FindFirst/FindNext */
- char *dir; /* the dir we are reading */
- struct dirent dent; /* the dirent to return */
- }
-DIR;
-
-/**********************************************************************
-* Implement dirent-style opendir/readdir/closedir on Window 95/NT
-*
-* Functions defined are opendir(), readdir() and closedir() with the
-* same prototypes as the normal dirent.h implementation.
-*
-* Does not implement telldir(), seekdir(), rewinddir() or scandir().
-* The dirent struct is compatible with Unix, except that d_ino is
-* always 1 and d_off is made up as we go along.
-*
-* Error codes are not available with errno but GetLastError.
-*
-* The DIR typedef is not compatible with Unix.
-**********************************************************************/
-
-static DIR * _dbus_opendir(const char *dir)
-{
- DIR *dp;
- char *filespec;
- HANDLE handle;
- int index;
-
- filespec = malloc(strlen(dir) + 2 + 1);
- strcpy(filespec, dir);
- index = strlen(filespec) - 1;
- if (index >= 0 && (filespec[index] == '/' || filespec[index] == '\\'))
- filespec[index] = '\0';
- strcat(filespec, "\\*");
-
- dp = (DIR *)malloc(sizeof(DIR));
- dp->offset = 0;
- dp->finished = 0;
- dp->dir = strdup(dir);
-
- handle = FindFirstFileA(filespec, &(dp->fileinfo));
- if (handle == INVALID_HANDLE_VALUE)
- {
- if (GetLastError() == ERROR_NO_MORE_FILES)
- dp->finished = 1;
- else
- return NULL;
- }
-
- dp->handle = handle;
- free(filespec);
-
- return dp;
-}
-
-static struct dirent * _dbus_readdir(DIR *dp)
-{
- int saved_err = GetLastError();
-
- if (!dp || dp->finished)
- return NULL;
-
- if (dp->offset != 0)
- {
- if (FindNextFileA(dp->handle, &(dp->fileinfo)) == 0)
- {
- if (GetLastError() == ERROR_NO_MORE_FILES)
- {
- SetLastError(saved_err);
- dp->finished = 1;
- }
- return NULL;
- }
- }
- dp->offset++;
-
- strncpy(dp->dent.d_name, dp->fileinfo.cFileName, _MAX_FNAME);
- dp->dent.d_ino = 1;
- dp->dent.d_reclen = strlen(dp->dent.d_name);
- dp->dent.d_off = dp->offset;
-
- return &(dp->dent);
-}
-
-
-static int _dbus_closedir(DIR *dp)
-{
- if (!dp)
- return 0;
- FindClose(dp->handle);
- if (dp->dir)
- free(dp->dir);
- if (dp)
- free(dp);
-
- return 0;
-}
-
-
/**
* Internals of directory iterator
*/
struct DBusDirIter
{
- DIR *d; /**< The DIR* from opendir() */
-
+ HANDLE handle;
+ WIN32_FIND_DATAA fileinfo; /* from FindFirst/FindNext */
+ dbus_bool_t finished; /* true if there are no more entries */
+ int offset;
};
/**
@@ -619,35 +479,66 @@ DBusDirIter*
_dbus_directory_open (const DBusString *filename,
DBusError *error)
{
- DIR *d;
DBusDirIter *iter;
- const char *filename_c;
+ DBusString filespec;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
- filename_c = _dbus_string_get_const_data (filename);
-
- d = _dbus_opendir (filename_c);
- if (d == NULL)
+ if (!_dbus_string_init_from_string (&filespec, filename))
{
- char *emsg = _dbus_win_error_string (GetLastError ());
- dbus_set_error (error, _dbus_win_error_from_last_error (),
- "Failed to read directory \"%s\": %s",
- filename_c, emsg);
- _dbus_win_free_error_string (emsg);
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+ "Could not allocate memory for directory filename copy");
return NULL;
}
+
+ if (_dbus_string_ends_with_c_str (&filespec, "/") || _dbus_string_ends_with_c_str (&filespec, "\\") )
+ {
+ if (!_dbus_string_append (&filespec, "*"))
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+ "Could not append filename wildcard");
+ return NULL;
+ }
+ }
+ else if (!_dbus_string_ends_with_c_str (&filespec, "*"))
+ {
+ if (!_dbus_string_append (&filespec, "\\*"))
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+ "Could not append filename wildcard 2");
+ return NULL;
+ }
+ }
+
iter = dbus_new0 (DBusDirIter, 1);
if (iter == NULL)
{
- _dbus_closedir (d);
+ _dbus_string_free (&filespec);
dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
"Could not allocate memory for directory iterator");
return NULL;
}
- iter->d = d;
-
+ iter->finished = FALSE;
+ iter->offset = 0;
+ iter->handle = FindFirstFileA (_dbus_string_get_const_data (&filespec), &(iter->fileinfo));
+ if (iter->handle == INVALID_HANDLE_VALUE)
+ {
+ if (GetLastError () == ERROR_NO_MORE_FILES)
+ iter->finished = TRUE;
+ else
+ {
+ char *emsg = _dbus_win_error_string (GetLastError ());
+ dbus_set_error (error, _dbus_win_error_from_last_error (),
+ "Failed to read directory \"%s\": %s",
+ _dbus_string_get_const_data (filename), emsg);
+ _dbus_win_free_error_string (emsg);
+ dbus_free ( iter );
+ _dbus_string_free (&filespec);
+ return NULL;
+ }
+ }
+ _dbus_string_free (&filespec);
return iter;
}
@@ -656,9 +547,6 @@ _dbus_directory_open (const DBusString *filename,
* UNIX. If an error occurs, the contents of "filename" are
* undefined. The error is never set if the function succeeds.
*
- * @todo for thread safety, I think we have to use
- * readdir_r(). (GLib has the same issue, should file a bug.)
- *
* @param iter the iterator
* @param filename string to be set to the next file in the dir
* @param error return location for error
@@ -669,40 +557,55 @@ _dbus_directory_get_next_file (DBusDirIter *iter,
DBusString *filename,
DBusError *error)
{
- struct dirent *ent;
+ int saved_err = GetLastError();
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
again:
SetLastError (0);
- ent = _dbus_readdir (iter->d);
- if (ent == NULL)
+
+ if (!iter || iter->finished)
+ return FALSE;
+
+ if (iter->offset > 0)
{
- if (GetLastError() != 0)
+ if (FindNextFileA (iter->handle, &(iter->fileinfo)) == 0)
{
- char *emsg = _dbus_win_error_string (GetLastError ());
- dbus_set_error (error, _dbus_win_error_from_last_error (),
- "Failed to get next in directory: %s", emsg);
- _dbus_win_free_error_string (emsg);
+ if (GetLastError() == ERROR_NO_MORE_FILES)
+ {
+ SetLastError(saved_err);
+ iter->finished = 1;
+ }
+ else
+ {
+ char *emsg = _dbus_win_error_string (GetLastError ());
+ dbus_set_error (error, _dbus_win_error_from_last_error (),
+ "Failed to get next in directory: %s", emsg);
+ _dbus_win_free_error_string (emsg);
+ return FALSE;
+ }
}
- 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
+
+ iter->offset++;
+
+ if (iter->finished)
+ return FALSE;
+
+ if (iter->fileinfo.cFileName[0] == '.' &&
+ (iter->fileinfo.cFileName[1] == '\0' ||
+ (iter->fileinfo.cFileName[1] == '.' && iter->fileinfo.cFileName[2] == '\0')))
+ goto again;
+
+ _dbus_string_set_length (filename, 0);
+ if (!_dbus_string_append (filename, iter->fileinfo.cFileName))
{
- _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");
- return FALSE;
- }
- else
- return TRUE;
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+ "No memory to read directory entry");
+ return FALSE;
}
+
+ return TRUE;
}
/**
@@ -711,7 +614,9 @@ again:
void
_dbus_directory_close (DBusDirIter *iter)
{
- _dbus_closedir (iter->d);
+ if (!iter)
+ return;
+ FindClose(iter->handle);
dbus_free (iter);
}
diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c
index 75f07e9c..b3b459f8 100644
--- a/dbus/dbus-sysdeps-win.c
+++ b/dbus/dbus-sysdeps-win.c
@@ -52,7 +52,6 @@
#include "dbus-credentials.h"
#include <windows.h>
-#include <ws2tcpip.h>
#include <wincrypt.h>
#include <iphlpapi.h>
@@ -376,7 +375,7 @@ _dbus_win_free_error_string (char *string)
*/
int
-_dbus_read_socket (int fd,
+_dbus_read_socket (DBusSocket fd,
DBusString *buffer,
int count)
{
@@ -398,8 +397,8 @@ _dbus_read_socket (int fd,
again:
- _dbus_verbose ("recv: count=%d fd=%d\n", count, fd);
- bytes_read = recv (fd, data, count, 0);
+ _dbus_verbose ("recv: count=%d fd=%Iu\n", count, fd.sock);
+ bytes_read = recv (fd.sock, data, count, 0);
if (bytes_read == SOCKET_ERROR)
{
@@ -446,7 +445,7 @@ _dbus_read_socket (int fd,
* @returns the number of bytes written or -1 on error
*/
int
-_dbus_write_socket (int fd,
+_dbus_write_socket (DBusSocket fd,
const DBusString *buffer,
int start,
int len)
@@ -458,8 +457,8 @@ _dbus_write_socket (int fd,
again:
- _dbus_verbose ("send: len=%d fd=%d\n", len, fd);
- bytes_written = send (fd, data, len, 0);
+ _dbus_verbose ("send: len=%d fd=%Iu\n", len, fd.sock);
+ bytes_written = send (fd.sock, data, len, 0);
if (bytes_written == SOCKET_ERROR)
{
@@ -490,13 +489,13 @@ _dbus_write_socket (int fd,
* @returns #FALSE if error set
*/
dbus_bool_t
-_dbus_close_socket (int fd,
+_dbus_close_socket (DBusSocket fd,
DBusError *error)
{
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
again:
- if (closesocket (fd) == SOCKET_ERROR)
+ if (closesocket (fd.sock) == SOCKET_ERROR)
{
DBUS_SOCKET_SET_ERRNO ();
@@ -504,11 +503,11 @@ _dbus_close_socket (int fd,
goto again;
dbus_set_error (error, _dbus_error_from_errno (errno),
- "Could not close socket: socket=%d, , %s",
- fd, _dbus_strerror_from_errno ());
+ "Could not close socket: socket=%Iu, , %s",
+ fd.sock, _dbus_strerror_from_errno ());
return FALSE;
}
- _dbus_verbose ("_dbus_close_socket: socket=%d, \n", fd);
+ _dbus_verbose ("_dbus_close_socket: socket=%Iu, \n", fd.sock);
return TRUE;
}
@@ -518,10 +517,10 @@ _dbus_close_socket (int fd,
* on exec. Should be called for all file
* descriptors in D-Bus code.
*
- * @param handle the Windows HANDLE
+ * @param handle the Windows HANDLE (a SOCKET is also OK)
*/
-void
-_dbus_fd_set_close_on_exec (intptr_t handle)
+static void
+_dbus_win_handle_set_close_on_exec (HANDLE handle)
{
if ( !SetHandleInformation( (HANDLE) handle,
HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE,
@@ -539,19 +538,19 @@ _dbus_fd_set_close_on_exec (intptr_t handle)
* @returns #TRUE on success.
*/
dbus_bool_t
-_dbus_set_fd_nonblocking (int handle,
- DBusError *error)
+_dbus_set_socket_nonblocking (DBusSocket handle,
+ DBusError *error)
{
u_long one = 1;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
- if (ioctlsocket (handle, FIONBIO, &one) == SOCKET_ERROR)
+ if (ioctlsocket (handle.sock, FIONBIO, &one) == SOCKET_ERROR)
{
DBUS_SOCKET_SET_ERRNO ();
dbus_set_error (error, _dbus_error_from_errno (errno),
- "Failed to set socket %d:%d to nonblocking: %s", handle,
- _dbus_strerror_from_errno ());
+ "Failed to set socket %Iu to nonblocking: %s",
+ handle.sock, _dbus_strerror_from_errno ());
return FALSE;
}
@@ -580,7 +579,7 @@ _dbus_set_fd_nonblocking (int handle,
* @returns total bytes written from both buffers, or -1 on error
*/
int
-_dbus_write_socket_two (int fd,
+_dbus_write_socket_two (DBusSocket fd,
const DBusString *buffer1,
int start1,
int len1,
@@ -619,8 +618,8 @@ _dbus_write_socket_two (int fd,
again:
- _dbus_verbose ("WSASend: len1+2=%d+%d fd=%d\n", len1, len2, fd);
- rc = WSASend (fd,
+ _dbus_verbose ("WSASend: len1+2=%d+%d fd=%Iu\n", len1, len2, fd.sock);
+ rc = WSASend (fd.sock,
vectors,
data2 ? 2 : 1,
&bytes_written,
@@ -643,12 +642,6 @@ _dbus_write_socket_two (int fd,
return bytes_written;
}
-dbus_bool_t
-_dbus_socket_is_invalid (int fd)
-{
- return fd == INVALID_SOCKET ? TRUE : FALSE;
-}
-
#if 0
/**
@@ -981,10 +974,10 @@ static BOOL is_winxp_sp3_or_lower()
/** Gets our SID
* @param sid points to sid buffer, need to be freed with LocalFree()
- * @param process_id the process id for which the sid should be returned
+ * @param process_id the process id for which the sid should be returned (use 0 for current process)
* @returns process sid
*/
-static dbus_bool_t
+dbus_bool_t
_dbus_getsid(char **sid, dbus_pid_t process_id)
{
HANDLE process_token = INVALID_HANDLE_VALUE;
@@ -993,7 +986,13 @@ _dbus_getsid(char **sid, dbus_pid_t process_id)
PSID psid;
int retval = FALSE;
- HANDLE process_handle = OpenProcess(is_winxp_sp3_or_lower() ? PROCESS_QUERY_INFORMATION : PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id);
+ HANDLE process_handle;
+ if (process_id == 0)
+ process_handle = GetCurrentProcess();
+ else if (is_winxp_sp3_or_lower())
+ process_handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, process_id);
+ else
+ process_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id);
if (!OpenProcessToken (process_handle, TOKEN_QUERY, &process_token))
{
@@ -1039,20 +1038,22 @@ failed:
************************************************************************/
/**
- * Creates a full-duplex pipe (as in socketpair()).
- * Sets both ends of the pipe nonblocking.
+ * Creates pair of connect sockets (as in socketpair()).
+ * Sets both ends of the pair nonblocking.
+ *
+ * Marks both file descriptors as close-on-exec
*
* @param fd1 return location for one end
* @param fd2 return location for the other end
- * @param blocking #TRUE if pipe should be blocking
+ * @param blocking #TRUE if pair 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)
+_dbus_socketpair (DBusSocket *fd1,
+ DBusSocket *fd2,
+ dbus_bool_t blocking,
+ DBusError *error)
{
SOCKET temp, socket1 = -1, socket2 = -1;
struct sockaddr_in saddr;
@@ -1133,11 +1134,11 @@ _dbus_full_duplex_pipe (int *fd1,
}
}
- *fd1 = socket1;
- *fd2 = socket2;
+ fd1->sock = socket1;
+ fd2->sock = socket2;
- _dbus_verbose ("full-duplex pipe %d:%d <-> %d:%d\n",
- *fd1, socket1, *fd2, socket2);
+ _dbus_verbose ("full-duplex pipe %Iu:%Iu <-> %Iu:%Iu\n",
+ fd1->sock, socket1, fd2->sock, socket2);
closesocket (temp);
@@ -1201,12 +1202,12 @@ _dbus_poll (DBusPollFD *fds,
if (fdp->events & _DBUS_POLLIN)
- msgp += sprintf (msgp, "R:%d ", fdp->fd);
+ msgp += sprintf (msgp, "R:%Iu ", fdp->fd.sock);
if (fdp->events & _DBUS_POLLOUT)
- msgp += sprintf (msgp, "W:%d ", fdp->fd);
+ msgp += sprintf (msgp, "W:%Iu ", fdp->fd.sock);
- msgp += sprintf (msgp, "E:%d\n\t", fdp->fd);
+ msgp += sprintf (msgp, "E:%Iu\n\t", fdp->fd.sock);
// FIXME: more robust code for long msg
// create on heap when msg[] becomes too small
@@ -1233,7 +1234,7 @@ _dbus_poll (DBusPollFD *fds,
if (fdp->events & _DBUS_POLLOUT)
lNetworkEvents |= FD_WRITE | FD_CONNECT;
- WSAEventSelect(fdp->fd, ev, lNetworkEvents);
+ WSAEventSelect(fdp->fd.sock, ev, lNetworkEvents);
pEvents[i] = ev;
}
@@ -1265,7 +1266,7 @@ _dbus_poll (DBusPollFD *fds,
fdp->revents = 0;
- WSAEnumNetworkEvents(fdp->fd, pEvents[i], &ne);
+ WSAEnumNetworkEvents(fdp->fd.sock, pEvents[i], &ne);
if (ne.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
fdp->revents |= _DBUS_POLLIN;
@@ -1277,20 +1278,20 @@ _dbus_poll (DBusPollFD *fds,
fdp->revents |= _DBUS_POLLERR;
if (ne.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
- msgp += sprintf (msgp, "R:%d ", fdp->fd);
+ msgp += sprintf (msgp, "R:%Iu ", fdp->fd.sock);
if (ne.lNetworkEvents & (FD_WRITE | FD_CONNECT))
- msgp += sprintf (msgp, "W:%d ", fdp->fd);
+ msgp += sprintf (msgp, "W:%Iu ", fdp->fd.sock);
if (ne.lNetworkEvents & (FD_OOB))
- msgp += sprintf (msgp, "E:%d ", fdp->fd);
+ msgp += sprintf (msgp, "E:%Iu ", fdp->fd.sock);
msgp += sprintf (msgp, "lNetworkEvents:%d ", ne.lNetworkEvents);
if(ne.lNetworkEvents)
ret++;
- WSAEventSelect(fdp->fd, pEvents[i], 0);
+ WSAEventSelect(fdp->fd.sock, pEvents[i], 0);
}
msgp += sprintf (msgp, "\n");
@@ -1319,7 +1320,7 @@ _dbus_poll (DBusPollFD *fds,
char *msgp;
fd_set read_set, write_set, err_set;
- int max_fd = 0;
+ SOCKET max_fd = 0;
int i;
struct timeval tv;
int ready;
@@ -1338,12 +1339,12 @@ _dbus_poll (DBusPollFD *fds,
if (fdp->events & _DBUS_POLLIN)
- msgp += sprintf (msgp, "R:%d ", fdp->fd);
+ msgp += sprintf (msgp, "R:%Iu ", fdp->fd.sock);
if (fdp->events & _DBUS_POLLOUT)
- msgp += sprintf (msgp, "W:%d ", fdp->fd);
+ msgp += sprintf (msgp, "W:%Iu ", fdp->fd.sock);
- msgp += sprintf (msgp, "E:%d\n\t", fdp->fd);
+ msgp += sprintf (msgp, "E:%Iu\n\t", fdp->fd.sock);
// FIXME: more robust code for long msg
// create on heap when msg[] becomes too small
@@ -1361,14 +1362,14 @@ _dbus_poll (DBusPollFD *fds,
DBusPollFD *fdp = &fds[i];
if (fdp->events & _DBUS_POLLIN)
- FD_SET (fdp->fd, &read_set);
+ FD_SET (fdp->fd.sock, &read_set);
if (fdp->events & _DBUS_POLLOUT)
- FD_SET (fdp->fd, &write_set);
+ FD_SET (fdp->fd.sock, &write_set);
- FD_SET (fdp->fd, &err_set);
+ FD_SET (fdp->fd.sock, &err_set);
- max_fd = MAX (max_fd, fdp->fd);
+ max_fd = MAX (max_fd, fdp->fd.sock);
}
// Avoid random lockups with send(), for lack of a better solution so far
@@ -1396,14 +1397,14 @@ _dbus_poll (DBusPollFD *fds,
{
DBusPollFD *fdp = &fds[i];
- if (FD_ISSET (fdp->fd, &read_set))
- msgp += sprintf (msgp, "R:%d ", fdp->fd);
+ if (FD_ISSET (fdp->fd.sock, &read_set))
+ msgp += sprintf (msgp, "R:%Iu ", fdp->fd.sock);
- if (FD_ISSET (fdp->fd, &write_set))
- msgp += sprintf (msgp, "W:%d ", fdp->fd);
+ if (FD_ISSET (fdp->fd.sock, &write_set))
+ msgp += sprintf (msgp, "W:%Iu ", fdp->fd.sock);
- if (FD_ISSET (fdp->fd, &err_set))
- msgp += sprintf (msgp, "E:%d\n\t", fdp->fd);
+ if (FD_ISSET (fdp->fd.sock, &err_set))
+ msgp += sprintf (msgp, "E:%Iu\n\t", fdp->fd.sock);
}
msgp += sprintf (msgp, "\n");
_dbus_verbose ("%s",msg);
@@ -1415,13 +1416,13 @@ _dbus_poll (DBusPollFD *fds,
fdp->revents = 0;
- if (FD_ISSET (fdp->fd, &read_set))
+ if (FD_ISSET (fdp->fd.sock, &read_set))
fdp->revents |= _DBUS_POLLIN;
- if (FD_ISSET (fdp->fd, &write_set))
+ if (FD_ISSET (fdp->fd.sock, &write_set))
fdp->revents |= _DBUS_POLLOUT;
- if (FD_ISSET (fdp->fd, &err_set))
+ if (FD_ISSET (fdp->fd.sock, &err_set))
fdp->revents |= _DBUS_POLLERR;
}
}
@@ -1485,7 +1486,7 @@ _dbus_exit (int code)
* @param error return location for error code
* @returns connection file descriptor or -1 on error
*/
-int
+DBusSocket
_dbus_connect_tcp_socket (const char *host,
const char *port,
const char *family,
@@ -1494,14 +1495,15 @@ _dbus_connect_tcp_socket (const char *host,
return _dbus_connect_tcp_socket_with_nonce (host, port, family, (const char*)NULL, error);
}
-int
+DBusSocket
_dbus_connect_tcp_socket_with_nonce (const char *host,
const char *port,
const char *family,
const char *noncefile,
DBusError *error)
{
- int fd = -1, res;
+ DBusSocket fd = DBUS_SOCKET_INIT;
+ int res;
struct addrinfo hints;
struct addrinfo *ai, *tmp;
@@ -1510,7 +1512,7 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
if (!_dbus_win_startup_winsock ())
{
_DBUS_SET_OOM (error);
- return -1;
+ return _dbus_socket_get_invalid ();
}
_DBUS_ZERO (hints);
@@ -1526,7 +1528,7 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
dbus_set_error (error,
DBUS_ERROR_INVALID_ARGS,
"Unknown address family %s", family);
- return -1;
+ return _dbus_socket_get_invalid ();
}
hints.ai_protocol = IPPROTO_TCP;
hints.ai_socktype = SOCK_STREAM;
@@ -1542,13 +1544,13 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
_dbus_error_from_errno (res),
"Failed to lookup host/port: \"%s:%s\": %s (%d)",
host, port, _dbus_strerror(res), res);
- return -1;
+ return _dbus_socket_get_invalid ();
}
tmp = ai;
while (tmp)
{
- if ((fd = socket (tmp->ai_family, SOCK_STREAM, 0)) == INVALID_SOCKET)
+ if ((fd.sock = socket (tmp->ai_family, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
DBUS_SOCKET_SET_ERRNO ();
dbus_set_error (error,
@@ -1556,15 +1558,15 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
"Failed to open socket: %s",
_dbus_strerror_from_errno ());
freeaddrinfo(ai);
- return -1;
+ return _dbus_socket_get_invalid ();
}
_DBUS_ASSERT_ERROR_IS_CLEAR(error);
- if (connect (fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) == SOCKET_ERROR)
+ if (connect (fd.sock, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) == SOCKET_ERROR)
{
DBUS_SOCKET_SET_ERRNO ();
- closesocket(fd);
- fd = -1;
+ closesocket(fd.sock);
+ fd.sock = INVALID_SOCKET;
tmp = tmp->ai_next;
continue;
}
@@ -1573,13 +1575,13 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
}
freeaddrinfo(ai);
- if (fd == -1)
+ if (!_dbus_socket_is_valid (fd))
{
dbus_set_error (error,
_dbus_error_from_errno (errno),
"Failed to connect to socket \"%s:%s\" %s",
host, port, _dbus_strerror_from_errno ());
- return -1;
+ return _dbus_socket_get_invalid ();
}
if (noncefile != NULL)
@@ -1589,9 +1591,9 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
if (!_dbus_string_init (&noncefileStr) ||
!_dbus_string_append(&noncefileStr, noncefile))
{
- closesocket (fd);
+ closesocket (fd.sock);
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
- return -1;
+ return _dbus_socket_get_invalid ();
}
ret = _dbus_send_nonce (fd, &noncefileStr, error);
@@ -1600,17 +1602,18 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
if (!ret)
{
- closesocket (fd);
- return -1;
+ closesocket (fd.sock);
+ return _dbus_socket_get_invalid ();
}
}
- _dbus_fd_set_close_on_exec (fd);
+ /* Every SOCKET is also a HANDLE. */
+ _dbus_win_handle_set_close_on_exec ((HANDLE) fd.sock);
- if (!_dbus_set_fd_nonblocking (fd, error))
+ if (!_dbus_set_socket_nonblocking (fd, error))
{
- closesocket (fd);
- return -1;
+ closesocket (fd.sock);
+ return _dbus_socket_get_invalid ();
}
return fd;
@@ -1636,10 +1639,11 @@ _dbus_listen_tcp_socket (const char *host,
const char *port,
const char *family,
DBusString *retport,
- int **fds_p,
+ DBusSocket **fds_p,
DBusError *error)
{
- int nlisten_fd = 0, *listen_fd = NULL, res, i, port_num = -1;
+ DBusSocket *listen_fd = NULL;
+ int nlisten_fd = 0, res, i, port_num = -1;
struct addrinfo hints;
struct addrinfo *ai, *tmp;
@@ -1665,7 +1669,7 @@ _dbus_listen_tcp_socket (const char *host,
_DBUS_ZERO (hints);
if (!family)
- hints.ai_family = AF_UNSPEC;
+ hints.ai_family = AF_INET;
else if (!strcmp(family, "ipv4"))
hints.ai_family = AF_INET;
else if (!strcmp(family, "ipv6"))
@@ -1699,8 +1703,8 @@ _dbus_listen_tcp_socket (const char *host,
tmp = ai;
while (tmp)
{
- int fd = -1, *newlisten_fd;
- if ((fd = socket (tmp->ai_family, SOCK_STREAM, 0)) == INVALID_SOCKET)
+ DBusSocket fd = DBUS_SOCKET_INIT, *newlisten_fd;
+ if ((fd.sock = socket (tmp->ai_family, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
DBUS_SOCKET_SET_ERRNO ();
dbus_set_error (error,
@@ -1711,10 +1715,10 @@ _dbus_listen_tcp_socket (const char *host,
}
_DBUS_ASSERT_ERROR_IS_CLEAR(error);
- if (bind (fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) == SOCKET_ERROR)
+ if (bind (fd.sock, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) == SOCKET_ERROR)
{
DBUS_SOCKET_SET_ERRNO ();
- closesocket (fd);
+ closesocket (fd.sock);
if (errno == WSAEADDRINUSE)
{
/* Calling this function with port=0 tries to
@@ -1730,20 +1734,20 @@ _dbus_listen_tcp_socket (const char *host,
goto failed;
}
- if (listen (fd, 30 /* backlog */) == SOCKET_ERROR)
+ if (listen (fd.sock, 30 /* backlog */) == SOCKET_ERROR)
{
DBUS_SOCKET_SET_ERRNO ();
dbus_set_error (error, _dbus_error_from_errno (errno),
"Failed to listen on socket \"%s:%s\": %s",
host ? host : "*", port, _dbus_strerror_from_errno ());
- closesocket (fd);
+ closesocket (fd.sock);
goto failed;
}
- newlisten_fd = dbus_realloc(listen_fd, sizeof(int)*(nlisten_fd+1));
+ newlisten_fd = dbus_realloc(listen_fd, sizeof(DBusSocket)*(nlisten_fd+1));
if (!newlisten_fd)
{
- closesocket (fd);
+ closesocket (fd.sock);
dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
"Failed to allocate file handle array");
goto failed;
@@ -1762,9 +1766,12 @@ _dbus_listen_tcp_socket (const char *host,
{
mysockaddr_gen addr;
socklen_t addrlen = sizeof(addr);
- char portbuf[10];
+ char portbuf[NI_MAXSERV];
- if (getsockname(fd, &addr.Address, &addrlen) == SOCKET_ERROR)
+ if (getsockname(fd.sock, &addr.Address, &addrlen) == SOCKET_ERROR ||
+ (res = getnameinfo (&addr.Address, addrlen, NULL, 0,
+ portbuf, sizeof(portbuf),
+ NI_NUMERICSERV)) != 0)
{
DBUS_SOCKET_SET_ERRNO ();
dbus_set_error (error, _dbus_error_from_errno (errno),
@@ -1772,10 +1779,6 @@ _dbus_listen_tcp_socket (const char *host,
host ? host : "*", port, _dbus_strerror_from_errno());
goto failed;
}
- if (addr.AddressIn.sin_family = AF_INET)
- snprintf( portbuf, sizeof( portbuf ) - 1, "%d", ntohs(addr.AddressIn.sin_port) );
- else
- snprintf( portbuf, sizeof( portbuf ) - 1, "%d", ntohs(addr.AddressIn6.sin6_port) );
if (!_dbus_string_append(retport, portbuf))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
@@ -1815,8 +1818,8 @@ _dbus_listen_tcp_socket (const char *host,
for (i = 0 ; i < nlisten_fd ; i++)
{
- _dbus_fd_set_close_on_exec (listen_fd[i]);
- if (!_dbus_set_fd_nonblocking (listen_fd[i], error))
+ _dbus_win_handle_set_close_on_exec ((HANDLE) listen_fd[i].sock);
+ if (!_dbus_set_socket_nonblocking (listen_fd[i], error))
{
goto failed;
}
@@ -1830,7 +1833,7 @@ _dbus_listen_tcp_socket (const char *host,
if (ai)
freeaddrinfo(ai);
for (i = 0 ; i < nlisten_fd ; i++)
- closesocket (listen_fd[i]);
+ closesocket (listen_fd[i].sock);
dbus_free(listen_fd);
return -1;
}
@@ -1843,22 +1846,22 @@ _dbus_listen_tcp_socket (const char *host,
* @param listen_fd the listen file descriptor
* @returns the connection fd of the client, or -1 on error
*/
-int
-_dbus_accept (int listen_fd)
+DBusSocket
+_dbus_accept (DBusSocket listen_fd)
{
- int client_fd;
+ DBusSocket client_fd;
retry:
- client_fd = accept (listen_fd, NULL, NULL);
+ client_fd.sock = accept (listen_fd.sock, NULL, NULL);
- if (DBUS_SOCKET_IS_INVALID (client_fd))
+ if (!_dbus_socket_is_valid (client_fd))
{
DBUS_SOCKET_SET_ERRNO ();
if (errno == EINTR)
goto retry;
}
- _dbus_verbose ("client fd %d accepted\n", client_fd);
+ _dbus_verbose ("client fd %Iu accepted\n", client_fd.sock);
return client_fd;
}
@@ -1867,8 +1870,8 @@ _dbus_accept (int listen_fd)
dbus_bool_t
-_dbus_send_credentials_socket (int handle,
- DBusError *error)
+_dbus_send_credentials_socket (DBusSocket handle,
+ DBusError *error)
{
/* FIXME: for the session bus credentials shouldn't matter (?), but
* for the system bus they are presumably essential. A rough outline
@@ -1944,7 +1947,7 @@ again:
* @returns #TRUE on success
*/
dbus_bool_t
-_dbus_read_credentials_socket (int handle,
+_dbus_read_credentials_socket (DBusSocket handle,
DBusCredentials *credentials,
DBusError *error)
{
@@ -1966,7 +1969,7 @@ _dbus_read_credentials_socket (int handle,
_dbus_string_free (&buf);
}
- pid = _dbus_get_peer_pid_from_tcp_handle (handle);
+ pid = _dbus_get_peer_pid_from_tcp_handle (handle.sock);
if (pid == 0)
return TRUE;
@@ -2250,11 +2253,13 @@ _dbus_create_directory (const DBusString *filename,
*
* @param str the string
* @param n_bytes the number of random bytes to append to string
- * @returns #TRUE on success, #FALSE if no memory
+ * @param error location to store reason for failure
+ * @returns #TRUE on success
*/
dbus_bool_t
_dbus_generate_random_bytes (DBusString *str,
- int n_bytes)
+ int n_bytes,
+ DBusError *error)
{
int old_len;
char *p;
@@ -2263,15 +2268,22 @@ _dbus_generate_random_bytes (DBusString *str,
old_len = _dbus_string_get_length (str);
if (!_dbus_string_lengthen (str, n_bytes))
- return FALSE;
+ {
+ _DBUS_SET_OOM (error);
+ return FALSE;
+ }
p = _dbus_string_get_data_len (str, old_len, n_bytes);
if (!CryptAcquireContext (&hprov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
- return FALSE;
+ {
+ _DBUS_SET_OOM (error);
+ return FALSE;
+ }
if (!CryptGenRandom (hprov, n_bytes, p))
{
+ _DBUS_SET_OOM (error);
CryptReleaseContext (hprov, 0);
return FALSE;
}
@@ -2957,8 +2969,11 @@ _dbus_daemon_publish_session_bus_address (const char* address, const char *scope
}
// create shm
+ dbus_uint64_t len = strlen( address ) + 1;
+
hDBusSharedMem = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
- 0, strlen( address ) + 1, _dbus_string_get_const_data(&shm_name) );
+ len >> 32, len & 0xffffffffu,
+ _dbus_string_get_const_data(&shm_name) );
_dbus_assert( hDBusSharedMem );
shared_addr = MapViewOfFile( hDBusSharedMem, FILE_MAP_WRITE, 0, 0, 0 );
@@ -3264,12 +3279,12 @@ _dbus_flush_caches (void)
* 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
+ * @returns #TRUE if e == EAGAIN or e == EWOULDBLOCK
*/
dbus_bool_t
-_dbus_get_is_errno_eagain_or_ewouldblock (void)
+_dbus_get_is_errno_eagain_or_ewouldblock (int e)
{
- return errno == WSAEWOULDBLOCK;
+ return e == WSAEWOULDBLOCK;
}
/**
@@ -3736,6 +3751,18 @@ _dbus_check_setuid (void)
return FALSE;
}
+int
+_dbus_save_socket_errno (void)
+{
+ return errno;
+}
+
+void
+_dbus_restore_socket_errno (int saved_errno)
+{
+ _dbus_win_set_errno (saved_errno);
+}
+
/** @} end of sysdeps-win */
/* tests in dbus-sysdeps-util.c */
diff --git a/dbus/dbus-sysdeps-win.h b/dbus/dbus-sysdeps-win.h
index 02e7a83f..a5367705 100644
--- a/dbus/dbus-sysdeps-win.h
+++ b/dbus/dbus-sysdeps-win.h
@@ -40,13 +40,16 @@ extern void *_dbus_win_get_dll_hmodule (void);
void _dbus_win_set_errno (int err);
+DBUS_PRIVATE_EXPORT
const char* _dbus_win_error_from_last_error (void);
dbus_bool_t _dbus_win_startup_winsock (void);
void _dbus_win_warn_win_error (const char *message,
unsigned long code);
+DBUS_PRIVATE_EXPORT
char * _dbus_win_error_string (int error_number);
+DBUS_PRIVATE_EXPORT
void _dbus_win_free_error_string (char *string);
extern const char* _dbus_lm_strerror (int error_number);
@@ -70,6 +73,7 @@ wchar_t *_dbus_win_utf8_to_utf16 (const char *str,
char *_dbus_win_utf16_to_utf8 (const wchar_t *str,
DBusError *error);
+DBUS_PRIVATE_EXPORT
void _dbus_win_set_error_from_win_error (DBusError *error, int code);
dbus_bool_t
@@ -80,14 +84,18 @@ _dbus_win_sid_to_name_and_domain (dbus_uid_t uid,
dbus_bool_t _dbus_file_exists (const char *filename);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_get_config_file_name(DBusString *config_file,
char *s);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_get_install_root(char *prefix, int len);
void _dbus_threads_windows_init_global (void);
void _dbus_threads_windows_ensure_ctor_linked (void);
+DBUS_PRIVATE_EXPORT
+dbus_bool_t _dbus_getsid(char **sid, dbus_pid_t process_id);
#endif
/** @} end of sysdeps-win.h */
diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c
index f4ba0fac..8b986d58 100644
--- a/dbus/dbus-sysdeps.c
+++ b/dbus/dbus-sysdeps.c
@@ -504,63 +504,37 @@ _dbus_string_parse_uint (const DBusString *str,
* @{
*/
-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_real_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
+ * @param error location to store reason for failure
+ * @returns #TRUE on success
*/
-void
-_dbus_generate_random_bytes_buffer (char *buffer,
- int n_bytes)
+dbus_bool_t
+_dbus_generate_random_bytes_buffer (char *buffer,
+ int n_bytes,
+ DBusError *error)
{
DBusString str;
if (!_dbus_string_init (&str))
{
- _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
- return;
+ _DBUS_SET_OOM (error);
+ return FALSE;
}
- if (!_dbus_generate_random_bytes (&str, n_bytes))
+ if (!_dbus_generate_random_bytes (&str, n_bytes, error))
{
_dbus_string_free (&str);
- _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
- return;
+ return FALSE;
}
_dbus_string_copy_to_buffer (&str, buffer, n_bytes);
_dbus_string_free (&str);
+ return TRUE;
}
/**
@@ -569,18 +543,20 @@ _dbus_generate_random_bytes_buffer (char *buffer,
*
* @param str the string
* @param n_bytes the number of random ASCII bytes to append to string
+ * @param error location to store reason for failure
* @returns #TRUE on success, #FALSE if no memory or other failure
*/
dbus_bool_t
_dbus_generate_random_ascii (DBusString *str,
- int n_bytes)
+ int n_bytes,
+ DBusError *error)
{
static const char letters[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
int i;
int len;
- if (!_dbus_generate_random_bytes (str, n_bytes))
+ if (!_dbus_generate_random_bytes (str, n_bytes, error))
return FALSE;
len = _dbus_string_get_length (str);
@@ -722,33 +698,23 @@ _dbus_set_errno_to_zero (void)
}
/**
- * 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
+ * @returns #TRUE if e == ENOMEM
*/
dbus_bool_t
-_dbus_get_is_errno_enomem (void)
+_dbus_get_is_errno_enomem (int e)
{
- return errno == ENOMEM;
+ return e == ENOMEM;
}
/**
* See if errno is EINTR
- * @returns #TRUE if errno == EINTR
+ * @returns #TRUE if e == EINTR
*/
dbus_bool_t
-_dbus_get_is_errno_eintr (void)
+_dbus_get_is_errno_eintr (int e)
{
- return errno == EINTR;
+ return e == EINTR;
}
/**
@@ -756,9 +722,9 @@ _dbus_get_is_errno_eintr (void)
* @returns #TRUE if errno == EPIPE
*/
dbus_bool_t
-_dbus_get_is_errno_epipe (void)
+_dbus_get_is_errno_epipe (int e)
{
- return errno == EPIPE;
+ return e == EPIPE;
}
/**
@@ -766,10 +732,10 @@ _dbus_get_is_errno_epipe (void)
* @returns #TRUE if errno == ETOOMANYREFS
*/
dbus_bool_t
-_dbus_get_is_errno_etoomanyrefs (void)
+_dbus_get_is_errno_etoomanyrefs (int e)
{
#ifdef ETOOMANYREFS
- return errno == ETOOMANYREFS;
+ return e == ETOOMANYREFS;
#else
return FALSE;
#endif
diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h
index 5465128e..7043a452 100644
--- a/dbus/dbus-sysdeps.h
+++ b/dbus/dbus-sysdeps.h
@@ -25,7 +25,10 @@
#ifndef DBUS_SYSDEPS_H
#define DBUS_SYSDEPS_H
+#ifndef VERSION
+#warning Please include config.h before dbus-sysdeps.h
#include "config.h"
+#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
@@ -59,6 +62,10 @@
#include "dbus-sysdeps-wince-glue.h"
#endif
+#ifdef DBUS_WIN
+#include <ws2tcpip.h>
+#endif
+
DBUS_BEGIN_DECLS
#ifdef DBUS_WIN
@@ -88,7 +95,9 @@ typedef struct DBusPipe DBusPipe;
void _dbus_abort (void) _DBUS_GNUC_NORETURN;
dbus_bool_t _dbus_check_setuid (void);
+DBUS_PRIVATE_EXPORT
const char* _dbus_getenv (const char *varname);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_clearenv (void);
char ** _dbus_get_environment (void);
@@ -113,27 +122,71 @@ typedef unsigned long dbus_gid_t;
/** 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.
- *
*/
+#ifdef DBUS_WIN
+
+typedef struct { SOCKET sock; } DBusSocket;
+# define DBUS_SOCKET_FORMAT "Iu"
+# define DBUS_SOCKET_INIT { INVALID_SOCKET }
+
+static inline SOCKET
+_dbus_socket_printable (DBusSocket s) { return s.sock; }
+
+static inline dbus_bool_t
+_dbus_socket_is_valid (DBusSocket s) { return s.sock != INVALID_SOCKET; }
+
+static inline void
+_dbus_socket_invalidate (DBusSocket *s) { s->sock = INVALID_SOCKET; }
+
+static inline int
+_dbus_socket_get_int (DBusSocket s) { return (int)s.sock; }
-dbus_bool_t _dbus_close_socket (int fd,
+#else /* not DBUS_WIN */
+
+typedef struct { int fd; } DBusSocket;
+# define DBUS_SOCKET_FORMAT "d"
+# define DBUS_SOCKET_INIT { -1 }
+
+static inline int
+_dbus_socket_printable (DBusSocket s) { return s.fd; }
+
+static inline dbus_bool_t
+_dbus_socket_is_valid (DBusSocket s) { return s.fd >= 0; }
+
+static inline void
+_dbus_socket_invalidate (DBusSocket *s) { s->fd = -1; }
+
+static inline int
+_dbus_socket_get_int (DBusSocket s) { return s.fd; }
+
+#endif /* not DBUS_WIN */
+
+static inline DBusSocket
+_dbus_socket_get_invalid (void)
+{
+ DBusSocket s = DBUS_SOCKET_INIT;
+
+ return s;
+}
+
+dbus_bool_t _dbus_set_socket_nonblocking (DBusSocket fd,
+ DBusError *error);
+
+DBUS_PRIVATE_EXPORT
+dbus_bool_t _dbus_close_socket (DBusSocket fd,
DBusError *error);
-int _dbus_read_socket (int fd,
+DBUS_PRIVATE_EXPORT
+int _dbus_read_socket (DBusSocket fd,
DBusString *buffer,
int count);
-int _dbus_write_socket (int fd,
+DBUS_PRIVATE_EXPORT
+int _dbus_write_socket (DBusSocket fd,
const DBusString *buffer,
int start,
int len);
-int _dbus_write_socket_two (int fd,
+int _dbus_write_socket_two (DBusSocket fd,
const DBusString *buffer1,
int start1,
int len1,
@@ -141,18 +194,19 @@ int _dbus_write_socket_two (int fd,
int start2,
int len2);
-int _dbus_read_socket_with_unix_fds (int fd,
+int _dbus_read_socket_with_unix_fds (DBusSocket fd,
DBusString *buffer,
int count,
int *fds,
int *n_fds);
-int _dbus_write_socket_with_unix_fds (int fd,
+DBUS_PRIVATE_EXPORT
+int _dbus_write_socket_with_unix_fds (DBusSocket fd,
const DBusString *buffer,
int start,
int len,
const int *fds,
int n_fds);
-int _dbus_write_socket_with_unix_fds_two (int fd,
+int _dbus_write_socket_with_unix_fds_two (DBusSocket fd,
const DBusString *buffer1,
int start1,
int len1,
@@ -162,35 +216,33 @@ int _dbus_write_socket_with_unix_fds_two (int fd,
const int *fds,
int n_fds);
-dbus_bool_t _dbus_socket_is_invalid (int fd);
-
-int _dbus_connect_tcp_socket (const char *host,
- const char *port,
- const char *family,
- DBusError *error);
-int _dbus_connect_tcp_socket_with_nonce (const char *host,
- const char *port,
- const char *family,
- const char *noncefile,
- DBusError *error);
+DBusSocket _dbus_connect_tcp_socket (const char *host,
+ const char *port,
+ const char *family,
+ DBusError *error);
+DBusSocket _dbus_connect_tcp_socket_with_nonce (const char *host,
+ const char *port,
+ const char *family,
+ const char *noncefile,
+ DBusError *error);
int _dbus_listen_tcp_socket (const char *host,
const char *port,
const char *family,
DBusString *retport,
- int **fds_p,
+ DBusSocket **fds_p,
DBusError *error);
-int _dbus_accept (int listen_fd);
+DBusSocket _dbus_accept (DBusSocket listen_fd);
-
-dbus_bool_t _dbus_read_credentials_socket (int client_fd,
+dbus_bool_t _dbus_read_credentials_socket (DBusSocket client_fd,
DBusCredentials *credentials,
DBusError *error);
-dbus_bool_t _dbus_send_credentials_socket (int server_fd,
+dbus_bool_t _dbus_send_credentials_socket (DBusSocket 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_PRIVATE_EXPORT
dbus_bool_t _dbus_append_user_from_current_process (DBusString *str);
dbus_bool_t _dbus_parse_unix_user_from_config (const DBusString *username,
@@ -214,7 +266,7 @@ dbus_bool_t _dbus_daemon_publish_session_bus_address (const char* address, const
void _dbus_daemon_unpublish_session_bus_address (void);
-dbus_bool_t _dbus_socket_can_pass_unix_fd(int fd);
+dbus_bool_t _dbus_socket_can_pass_unix_fd(DBusSocket fd);
/** Opaque type representing an atomically-modifiable integer
* that can be used from multiple threads.
@@ -304,40 +356,99 @@ dbus_int32_t _dbus_atomic_get (DBusAtomic *atomic);
#define _DBUS_POLLNVAL 0x0020
#endif
+#ifdef DBUS_WIN
+
+/* On Windows, you can only poll sockets. We emulate Unix poll() using
+ * select(), so it doesn't matter what precise type we put in DBusPollFD;
+ * use DBusSocket so that the compiler can check we are doing it right.
+ */
+typedef DBusSocket DBusPollable;
+# define DBUS_POLLABLE_FORMAT "Iu"
+
+static inline DBusPollable
+_dbus_socket_get_pollable (DBusSocket s) { return s; }
+
+static inline SOCKET
+_dbus_pollable_printable (DBusPollable p) { return p.sock; }
+
+static inline dbus_bool_t
+_dbus_pollable_is_valid (DBusPollable p) { return _dbus_socket_is_valid (p); }
+
+static inline void
+_dbus_pollable_invalidate (DBusPollable *p) { _dbus_socket_invalidate (p); }
+
+static inline dbus_bool_t
+_dbus_pollable_equals (DBusPollable a, DBusPollable b) { return a.sock == b.sock; }
+
+#else /* !DBUS_WIN */
+
+/* On Unix, you can poll sockets, pipes, etc., and we must put exactly
+ * "int" in DBusPollFD because we're relying on its layout exactly matching
+ * struct pollfd. (This is silly, and one day we should use a better
+ * abstraction.)
+ */
+typedef int DBusPollable;
+# define DBUS_POLLABLE_FORMAT "d"
+
+static inline DBusPollable
+_dbus_socket_get_pollable (DBusSocket s) { return s.fd; }
+
+static inline int
+_dbus_pollable_printable (DBusPollable p) { return p; }
+
+static inline dbus_bool_t
+_dbus_pollable_is_valid (DBusPollable p) { return p >= 0; }
+
+static inline void
+_dbus_pollable_invalidate (DBusPollable *p) { *p = -1; }
+
+static inline dbus_bool_t
+_dbus_pollable_equals (DBusPollable a, DBusPollable b) { return a == b; }
+
+#endif /* !DBUS_WIN */
+
/**
* A portable struct pollfd wrapper.
*/
typedef struct
{
- int fd; /**< File descriptor */
+ DBusPollable fd; /**< File descriptor */
short events; /**< Events to poll for */
short revents; /**< Events that occurred */
} DBusPollFD;
+DBUS_PRIVATE_EXPORT
int _dbus_poll (DBusPollFD *fds,
int n_fds,
int timeout_milliseconds);
+DBUS_PRIVATE_EXPORT
void _dbus_sleep_milliseconds (int milliseconds);
+DBUS_PRIVATE_EXPORT
void _dbus_get_monotonic_time (long *tv_sec,
long *tv_usec);
+DBUS_PRIVATE_EXPORT
void _dbus_get_real_time (long *tv_sec,
long *tv_usec);
/**
* directory interface
*/
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_create_directory (const DBusString *filename,
DBusError *error);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_delete_directory (const DBusString *filename,
DBusError *error);
+DBUS_PRIVATE_EXPORT
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_PRIVATE_EXPORT
dbus_bool_t _dbus_path_is_absolute (const DBusString *filename);
dbus_bool_t _dbus_get_standard_session_servicedirs (DBusList **dirs);
@@ -359,39 +470,46 @@ 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 (intptr_t fd);
-
+DBUS_PRIVATE_EXPORT
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_GNUC_WARN_UNUSED_RESULT
+dbus_bool_t _dbus_generate_random_bytes_buffer (char *buffer,
+ int n_bytes,
+ DBusError *error);
dbus_bool_t _dbus_generate_random_bytes (DBusString *str,
- int n_bytes);
+ int n_bytes,
+ DBusError *error);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_generate_random_ascii (DBusString *str,
- int n_bytes);
+ int n_bytes,
+ DBusError *error);
+DBUS_PRIVATE_EXPORT
const char* _dbus_error_from_errno (int error_number);
+DBUS_PRIVATE_EXPORT
const char* _dbus_error_from_system_errno (void);
+int _dbus_save_socket_errno (void);
+void _dbus_restore_socket_errno (int saved_errno);
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);
-dbus_bool_t _dbus_get_is_errno_etoomanyrefs (void);
+dbus_bool_t _dbus_get_is_errno_eagain_or_ewouldblock (int e);
+dbus_bool_t _dbus_get_is_errno_enomem (int e);
+dbus_bool_t _dbus_get_is_errno_eintr (int e);
+dbus_bool_t _dbus_get_is_errno_epipe (int e);
+dbus_bool_t _dbus_get_is_errno_etoomanyrefs (int e);
+DBUS_PRIVATE_EXPORT
const char* _dbus_strerror_from_errno (void);
void _dbus_disable_sigpipe (void);
-
+DBUS_PRIVATE_EXPORT
void _dbus_exit (int code) _DBUS_GNUC_NORETURN;
+DBUS_PRIVATE_EXPORT
int _dbus_printf_string_upper_bound (const char *format,
va_list args);
@@ -414,10 +532,11 @@ typedef struct
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);
+DBUS_PRIVATE_EXPORT
+dbus_bool_t _dbus_socketpair (DBusSocket *fd1,
+ DBusSocket *fd2,
+ dbus_bool_t blocking,
+ DBusError *error);
void _dbus_print_backtrace (void);
@@ -453,6 +572,7 @@ void _dbus_init_system_log (dbus_bool_t is_daemon);
typedef enum {
DBUS_SYSTEM_LOG_INFO,
+ DBUS_SYSTEM_LOG_WARNING,
DBUS_SYSTEM_LOG_SECURITY,
DBUS_SYSTEM_LOG_FATAL
} DBusSystemLogSeverity;
@@ -529,6 +649,7 @@ void _dbus_threads_lock_platform_specific (void);
*/
void _dbus_threads_unlock_platform_specific (void);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_split_paths_and_append (DBusString *dirs,
const char *suffix,
DBusList **dir_list);
@@ -539,11 +660,13 @@ unsigned long _dbus_pid_for_log (void);
* the PID file handling just needs a little more abstraction
* in the bus daemon first.
*/
+DBUS_PRIVATE_EXPORT
dbus_pid_t _dbus_getpid (void);
dbus_bool_t _dbus_change_to_daemon_user (const char *user,
DBusError *error);
+DBUS_PRIVATE_EXPORT
void _dbus_flush_caches (void);
/*
diff --git a/dbus/dbus-test-main.c b/dbus/dbus-test-main.c
index f6ef7821..9a80f853 100644
--- a/dbus/dbus-test-main.c
+++ b/dbus/dbus-test-main.c
@@ -31,6 +31,10 @@
#include <locale.h>
#endif
+#ifdef DBUS_UNIX
+# include <dbus/dbus-sysdeps-unix.h>
+#endif
+
int
main (int argc,
char **argv)
@@ -38,6 +42,11 @@ main (int argc,
const char *test_data_dir;
const char *specific_test;
+#ifdef DBUS_UNIX
+ /* close any inherited fds so dbus-spawn's check for close-on-exec works */
+ _dbus_close_all ();
+#endif
+
#if HAVE_SETLOCALE
setlocale(LC_ALL, "");
#endif
diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h
index f254388b..71876a10 100644
--- a/dbus/dbus-test.h
+++ b/dbus/dbus-test.h
@@ -28,29 +28,72 @@
#include <dbus/dbus-string.h>
#include <dbus/dbus-marshal-validate.h>
+/* Only things that are in libdbus-1.la and used from libdbus-internal.la
+ * need to have DBUS_PRIVATE_EXPORT. If you get
+ *
+ * warning: 'foo' redeclared without dllimport attribute: previous
+ * dllimport ignored [-Wattributes]
+ *
+ * then you have added too many.
+ */
+
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_hash_test (void);
+
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_list_test (void);
+
+DBUS_PRIVATE_EXPORT
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_validate_test (void);
+
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_misc_test (void);
+
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_signature_test (void);
+
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_mem_pool_test (void);
+
dbus_bool_t _dbus_string_test (void);
+
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_address_test (void);
+
+DBUS_PRIVATE_EXPORT
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_PRIVATE_EXPORT
dbus_bool_t _dbus_sha_test (const char *test_data_dir);
+
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_keyring_test (void);
+
+DBUS_PRIVATE_EXPORT
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_PRIVATE_EXPORT
dbus_bool_t _dbus_userdb_test (const char *test_data_dir);
+
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_transport_unix_test (void);
+
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_memory_test (void);
+
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_object_tree_test (void);
+
dbus_bool_t _dbus_credentials_test (const char *test_data_dir);
void dbus_internal_do_not_use_run_tests (const char *test_data_dir,
diff --git a/dbus/dbus-threads-internal.h b/dbus/dbus-threads-internal.h
index 64e8bac0..076acd26 100644
--- a/dbus/dbus-threads-internal.h
+++ b/dbus/dbus-threads-internal.h
@@ -48,7 +48,9 @@ typedef struct DBusCMutex DBusCMutex;
DBUS_BEGIN_DECLS
+DBUS_PRIVATE_EXPORT
void _dbus_rmutex_lock (DBusRMutex *mutex);
+DBUS_PRIVATE_EXPORT
void _dbus_rmutex_unlock (DBusRMutex *mutex);
void _dbus_rmutex_new_at_location (DBusRMutex **location_p);
void _dbus_rmutex_free_at_location (DBusRMutex **location_p);
diff --git a/dbus/dbus-timeout.h b/dbus/dbus-timeout.h
index d0a8af4a..c652bb7b 100644
--- a/dbus/dbus-timeout.h
+++ b/dbus/dbus-timeout.h
@@ -40,14 +40,18 @@ typedef struct DBusTimeoutList DBusTimeoutList;
/** function to run when the timeout is handled */
typedef dbus_bool_t (* DBusTimeoutHandler) (void *data);
+DBUS_PRIVATE_EXPORT
DBusTimeout* _dbus_timeout_new (int interval,
DBusTimeoutHandler handler,
void *data,
DBusFreeFunction free_data_function);
DBusTimeout* _dbus_timeout_ref (DBusTimeout *timeout);
+DBUS_PRIVATE_EXPORT
void _dbus_timeout_unref (DBusTimeout *timeout);
+DBUS_PRIVATE_EXPORT
void _dbus_timeout_set_interval (DBusTimeout *timeout,
int interval);
+DBUS_PRIVATE_EXPORT
void _dbus_timeout_set_enabled (DBusTimeout *timeout,
dbus_bool_t enabled);
diff --git a/dbus/dbus-transport-protected.h b/dbus/dbus-transport-protected.h
index 396f0ffd..ee627a3a 100644
--- a/dbus/dbus-transport-protected.h
+++ b/dbus/dbus-transport-protected.h
@@ -67,7 +67,7 @@ struct DBusTransportVTable
/**< Outstanding messages counter changed */
dbus_bool_t (* get_socket_fd) (DBusTransport *transport,
- int *fd_p);
+ DBusSocket *fd_p);
/**< Get socket file descriptor */
};
diff --git a/dbus/dbus-transport-socket.c b/dbus/dbus-transport-socket.c
index 199d3b54..35c3cbfc 100644
--- a/dbus/dbus-transport-socket.c
+++ b/dbus/dbus-transport-socket.c
@@ -49,7 +49,7 @@ typedef struct DBusTransportSocket DBusTransportSocket;
struct DBusTransportSocket
{
DBusTransport base; /**< Parent instance */
- int fd; /**< File descriptor. */
+ DBusSocket fd; /**< File descriptor. */
DBusWatch *read_watch; /**< Watch for readability. */
DBusWatch *write_watch; /**< Watch for writability. */
@@ -159,9 +159,9 @@ check_write_watch (DBusTransport *transport)
}
}
- _dbus_verbose ("check_write_watch(): needed = %d on connection %p watch %p fd = %d outgoing messages exist %d\n",
+ _dbus_verbose ("check_write_watch(): needed = %d on connection %p watch %p fd = %" DBUS_SOCKET_FORMAT " outgoing messages exist %d\n",
needed, transport->connection, socket_transport->write_watch,
- socket_transport->fd,
+ _dbus_socket_printable (socket_transport->fd),
_dbus_connection_has_messages_to_send_unlocked (transport->connection));
_dbus_connection_toggle_watch_unlocked (transport->connection,
@@ -177,7 +177,8 @@ check_read_watch (DBusTransport *transport)
DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
dbus_bool_t need_read_watch;
- _dbus_verbose ("fd = %d\n",socket_transport->fd);
+ _dbus_verbose ("fd = %" DBUS_SOCKET_FORMAT "\n",
+ _dbus_socket_printable (socket_transport->fd));
if (transport->connection == NULL)
return;
@@ -247,13 +248,15 @@ read_data_into_auth (DBusTransport *transport,
DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
DBusString *buffer;
int bytes_read;
-
+ int saved_errno;
+
*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);
+ saved_errno = _dbus_save_socket_errno ();
_dbus_auth_return_buffer (transport->auth, buffer);
@@ -267,16 +270,16 @@ read_data_into_auth (DBusTransport *transport,
{
/* EINTR already handled for us */
- if (_dbus_get_is_errno_enomem ())
+ if (_dbus_get_is_errno_enomem (saved_errno))
{
*oom = TRUE;
}
- else if (_dbus_get_is_errno_eagain_or_ewouldblock ())
+ else if (_dbus_get_is_errno_eagain_or_ewouldblock (saved_errno))
; /* do nothing, just return FALSE below */
else
{
_dbus_verbose ("Error reading from remote app: %s\n",
- _dbus_strerror_from_errno ());
+ _dbus_strerror (saved_errno));
do_io_error (transport);
}
@@ -299,6 +302,7 @@ write_data_from_auth (DBusTransport *transport)
{
DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
int bytes_written;
+ int saved_errno;
const DBusString *buffer;
if (!_dbus_auth_get_bytes_to_send (transport->auth,
@@ -308,6 +312,7 @@ write_data_from_auth (DBusTransport *transport)
bytes_written = _dbus_write_socket (socket_transport->fd,
buffer,
0, _dbus_string_get_length (buffer));
+ saved_errno = _dbus_save_socket_errno ();
if (bytes_written > 0)
{
@@ -318,12 +323,12 @@ write_data_from_auth (DBusTransport *transport)
{
/* EINTR already handled for us */
- if (_dbus_get_is_errno_eagain_or_ewouldblock ())
+ if (_dbus_get_is_errno_eagain_or_ewouldblock (saved_errno))
;
else
{
_dbus_verbose ("Error writing to remote app: %s\n",
- _dbus_strerror_from_errno ());
+ _dbus_strerror (saved_errno));
do_io_error (transport);
}
}
@@ -510,9 +515,9 @@ do_writing (DBusTransport *transport)
}
#if 1
- _dbus_verbose ("do_writing(), have_messages = %d, fd = %d\n",
+ _dbus_verbose ("do_writing(), have_messages = %d, fd = %" DBUS_SOCKET_FORMAT "\n",
_dbus_connection_has_messages_to_send_unlocked (transport->connection),
- socket_transport->fd);
+ _dbus_socket_printable (socket_transport->fd));
#endif
oom = FALSE;
@@ -527,6 +532,7 @@ do_writing (DBusTransport *transport)
const DBusString *body;
int header_len, body_len;
int total_bytes_to_write;
+ int saved_errno;
if (total > socket_transport->max_bytes_written_per_iteration)
{
@@ -584,6 +590,7 @@ do_writing (DBusTransport *transport)
&socket_transport->encoded_outgoing,
socket_transport->message_bytes_written,
total_bytes_to_write - socket_transport->message_bytes_written);
+ saved_errno = _dbus_save_socket_errno ();
}
else
{
@@ -612,6 +619,7 @@ do_writing (DBusTransport *transport)
0, body_len,
unix_fds,
n);
+ saved_errno = _dbus_save_socket_errno ();
if (bytes_written > 0 && n > 0)
_dbus_verbose("Wrote %i unix fds\n", n);
@@ -638,6 +646,8 @@ do_writing (DBusTransport *transport)
body_len -
(socket_transport->message_bytes_written - header_len));
}
+
+ saved_errno = _dbus_save_socket_errno ();
}
}
@@ -651,7 +661,7 @@ do_writing (DBusTransport *transport)
* http://lists.freedesktop.org/archives/dbus/2008-March/009526.html
*/
- if (_dbus_get_is_errno_eagain_or_ewouldblock () || _dbus_get_is_errno_epipe ())
+ if (_dbus_get_is_errno_eagain_or_ewouldblock (saved_errno) || _dbus_get_is_errno_epipe (saved_errno))
goto out;
/* Since Linux commit 25888e (from 2.6.37-rc4, Nov 2010), sendmsg()
@@ -663,7 +673,7 @@ do_writing (DBusTransport *transport)
* https://bugs.freedesktop.org/show_bug.cgi?id=80163
*/
- else if (_dbus_get_is_errno_etoomanyrefs ())
+ else if (_dbus_get_is_errno_etoomanyrefs (saved_errno))
{
/* We only send fds in the first byte of the message.
* ETOOMANYREFS cannot happen after.
@@ -686,7 +696,7 @@ do_writing (DBusTransport *transport)
else
{
_dbus_verbose ("Error writing to remote app: %s\n",
- _dbus_strerror_from_errno ());
+ _dbus_strerror (saved_errno));
do_io_error (transport);
goto out;
}
@@ -730,8 +740,10 @@ do_reading (DBusTransport *transport)
int bytes_read;
int total;
dbus_bool_t oom;
+ int saved_errno;
- _dbus_verbose ("fd = %d\n",socket_transport->fd);
+ _dbus_verbose ("fd = %" DBUS_SOCKET_FORMAT "\n",
+ _dbus_socket_printable (socket_transport->fd));
/* No messages without authentication! */
if (!_dbus_transport_try_to_authenticate (transport))
@@ -774,6 +786,8 @@ do_reading (DBusTransport *transport)
&socket_transport->encoded_incoming,
socket_transport->max_bytes_read_per_iteration);
+ saved_errno = _dbus_save_socket_errno ();
+
_dbus_assert (_dbus_string_get_length (&socket_transport->encoded_incoming) ==
bytes_read);
@@ -823,6 +837,7 @@ do_reading (DBusTransport *transport)
buffer,
socket_transport->max_bytes_read_per_iteration,
fds, &n_fds);
+ saved_errno = _dbus_save_socket_errno ();
if (bytes_read >= 0 && n_fds > 0)
_dbus_verbose("Read %i unix fds\n", n_fds);
@@ -834,28 +849,29 @@ do_reading (DBusTransport *transport)
{
bytes_read = _dbus_read_socket (socket_transport->fd,
buffer, socket_transport->max_bytes_read_per_iteration);
+ saved_errno = _dbus_save_socket_errno ();
}
_dbus_message_loader_return_buffer (transport->loader,
buffer);
}
-
+
if (bytes_read < 0)
{
/* EINTR already handled for us */
- if (_dbus_get_is_errno_enomem ())
+ if (_dbus_get_is_errno_enomem (saved_errno))
{
_dbus_verbose ("Out of memory in read()/do_reading()\n");
oom = TRUE;
goto out;
}
- else if (_dbus_get_is_errno_eagain_or_ewouldblock ())
+ else if (_dbus_get_is_errno_eagain_or_ewouldblock (saved_errno))
goto out;
else
{
_dbus_verbose ("Error reading from remote app: %s\n",
- _dbus_strerror_from_errno ());
+ _dbus_strerror (saved_errno));
do_io_error (transport);
goto out;
}
@@ -993,7 +1009,7 @@ socket_handle_watch (DBusTransport *transport,
_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",
+ _dbus_verbose ("asked to handle watch %p on fd %" DBUS_SOCKET_FORMAT " that we don't recognize\n",
watch, dbus_watch_get_socket (watch));
}
#endif /* DBUS_ENABLE_VERBOSE_MODE */
@@ -1011,7 +1027,7 @@ socket_disconnect (DBusTransport *transport)
free_watches (transport);
_dbus_close_socket (socket_transport->fd, NULL);
- socket_transport->fd = -1;
+ _dbus_socket_invalidate (&socket_transport->fd);
}
static dbus_bool_t
@@ -1062,13 +1078,13 @@ socket_do_iteration (DBusTransport *transport,
int poll_res;
int poll_timeout;
- _dbus_verbose (" iteration flags = %s%s timeout = %d read_watch = %p write_watch = %p fd = %d\n",
+ _dbus_verbose (" iteration flags = %s%s timeout = %d read_watch = %p write_watch = %p fd = %" DBUS_SOCKET_FORMAT "\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);
+ _dbus_socket_printable (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
@@ -1076,7 +1092,7 @@ socket_do_iteration (DBusTransport *transport,
* we don't want to read any messages yet if not given DO_READING.
*/
- poll_fd.fd = socket_transport->fd;
+ poll_fd.fd = _dbus_socket_get_pollable (socket_transport->fd);
poll_fd.events = 0;
if (_dbus_transport_try_to_authenticate (transport))
@@ -1129,6 +1145,8 @@ socket_do_iteration (DBusTransport *transport,
if (poll_fd.events)
{
+ int saved_errno;
+
if (flags & DBUS_ITERATION_BLOCK)
poll_timeout = timeout_milliseconds;
else
@@ -1147,8 +1165,9 @@ socket_do_iteration (DBusTransport *transport,
again:
poll_res = _dbus_poll (&poll_fd, 1, poll_timeout);
+ saved_errno = _dbus_save_socket_errno ();
- if (poll_res < 0 && _dbus_get_is_errno_eintr ())
+ if (poll_res < 0 && _dbus_get_is_errno_eintr (saved_errno))
goto again;
if (flags & DBUS_ITERATION_BLOCK)
@@ -1191,7 +1210,7 @@ socket_do_iteration (DBusTransport *transport,
else
{
_dbus_verbose ("Error from _dbus_poll(): %s\n",
- _dbus_strerror_from_errno ());
+ _dbus_strerror (saved_errno));
}
}
@@ -1222,7 +1241,7 @@ socket_live_messages_changed (DBusTransport *transport)
static dbus_bool_t
socket_get_socket_fd (DBusTransport *transport,
- int *fd_p)
+ DBusSocket *fd_p)
{
DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
@@ -1253,7 +1272,7 @@ static const DBusTransportVTable socket_vtable = {
* @returns the new transport, or #NULL if no memory.
*/
DBusTransport*
-_dbus_transport_new_for_socket (int fd,
+_dbus_transport_new_for_socket (DBusSocket fd,
const DBusString *server_guid,
const DBusString *address)
{
@@ -1269,14 +1288,14 @@ _dbus_transport_new_for_socket (int fd,
if (!_dbus_string_init (&socket_transport->encoded_incoming))
goto failed_1;
- socket_transport->write_watch = _dbus_watch_new (fd,
+ socket_transport->write_watch = _dbus_watch_new (_dbus_socket_get_pollable (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,
+ socket_transport->read_watch = _dbus_watch_new (_dbus_socket_get_pollable (fd),
DBUS_WATCH_READABLE,
FALSE,
NULL, NULL, NULL);
@@ -1334,7 +1353,7 @@ _dbus_transport_new_for_tcp_socket (const char *host,
const char *noncefile,
DBusError *error)
{
- int fd;
+ DBusSocket fd;
DBusTransport *transport;
DBusString address;
@@ -1371,7 +1390,7 @@ _dbus_transport_new_for_tcp_socket (const char *host,
goto error;
fd = _dbus_connect_tcp_socket_with_nonce (host, port, family, noncefile, error);
- if (fd < 0)
+ if (!_dbus_socket_is_valid (fd))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
_dbus_string_free (&address);
@@ -1387,7 +1406,7 @@ _dbus_transport_new_for_tcp_socket (const char *host,
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
_dbus_close_socket (fd, NULL);
- fd = -1;
+ _dbus_socket_invalidate (&fd);
}
return transport;
diff --git a/dbus/dbus-transport-socket.h b/dbus/dbus-transport-socket.h
index 8aefae37..b8267ff6 100644
--- a/dbus/dbus-transport-socket.h
+++ b/dbus/dbus-transport-socket.h
@@ -27,7 +27,7 @@
DBUS_BEGIN_DECLS
-DBusTransport* _dbus_transport_new_for_socket (int fd,
+DBusTransport* _dbus_transport_new_for_socket (DBusSocket fd,
const DBusString *server_guid,
const DBusString *address);
DBusTransport* _dbus_transport_new_for_tcp_socket (const char *host,
diff --git a/dbus/dbus-transport-unix.c b/dbus/dbus-transport-unix.c
index 9a9fea50..f2b1f092 100644
--- a/dbus/dbus-transport-unix.c
+++ b/dbus/dbus-transport-unix.c
@@ -59,7 +59,7 @@ _dbus_transport_new_for_domain_socket (const char *path,
dbus_bool_t abstract,
DBusError *error)
{
- int fd;
+ DBusSocket fd = DBUS_SOCKET_INIT;
DBusTransport *transport;
DBusString address;
@@ -71,8 +71,6 @@ _dbus_transport_new_for_domain_socket (const char *path,
return NULL;
}
- fd = -1;
-
if ((abstract &&
!_dbus_string_append (&address, "unix:abstract=")) ||
(!abstract &&
@@ -83,8 +81,8 @@ _dbus_transport_new_for_domain_socket (const char *path,
goto failed_0;
}
- fd = _dbus_connect_unix_socket (path, abstract, error);
- if (fd < 0)
+ fd.fd = _dbus_connect_unix_socket (path, abstract, error);
+ if (fd.fd < 0)
{
_DBUS_ASSERT_ERROR_IS_SET (error);
goto failed_0;
@@ -127,7 +125,7 @@ _dbus_transport_new_for_exec (const char *path,
char *const argv[],
DBusError *error)
{
- int fd;
+ DBusSocket fd = DBUS_SOCKET_INIT;
DBusTransport *transport;
DBusString address;
unsigned i;
@@ -141,8 +139,6 @@ _dbus_transport_new_for_exec (const char *path,
return NULL;
}
- fd = -1;
-
escaped = dbus_address_escape_value (path);
if (!escaped)
{
@@ -184,8 +180,8 @@ _dbus_transport_new_for_exec (const char *path,
}
}
- fd = _dbus_connect_exec (path, argv, error);
- if (fd < 0)
+ fd.fd = _dbus_connect_exec (path, argv, error);
+ if (fd.fd < 0)
{
_DBUS_ASSERT_ERROR_IS_SET (error);
goto failed;
@@ -206,7 +202,7 @@ _dbus_transport_new_for_exec (const char *path,
return transport;
failed:
- if (fd >= 0)
+ if (fd.fd >= 0)
_dbus_close_socket (fd, NULL);
_dbus_string_free (&address);
diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c
index e9dcc568..31586b1c 100644
--- a/dbus/dbus-transport.c
+++ b/dbus/dbus-transport.c
@@ -949,7 +949,7 @@ _dbus_transport_set_connection (DBusTransport *transport,
*/
dbus_bool_t
_dbus_transport_get_socket_fd (DBusTransport *transport,
- int *fd_p)
+ DBusSocket *fd_p)
{
dbus_bool_t retval;
@@ -1425,6 +1425,33 @@ _dbus_transport_set_unix_user_function (DBusTransport *transport,
transport->free_unix_user_data = free_data_function;
}
+dbus_bool_t
+_dbus_transport_get_linux_security_label (DBusTransport *transport,
+ char **label_p)
+{
+ DBusCredentials *auth_identity;
+
+ *label_p = NULL;
+
+ if (!transport->authenticated)
+ return FALSE;
+
+ auth_identity = _dbus_auth_get_identity (transport->auth);
+
+ if (_dbus_credentials_include (auth_identity,
+ DBUS_CREDENTIAL_LINUX_SECURITY_LABEL))
+ {
+ /* If no memory, we are supposed to return TRUE and set NULL */
+ *label_p = _dbus_strdup (_dbus_credentials_get_linux_security_label (auth_identity));
+
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
/**
* See dbus_connection_get_windows_user().
*
diff --git a/dbus/dbus-transport.h b/dbus/dbus-transport.h
index 39c74c46..9e3787dd 100644
--- a/dbus/dbus-transport.h
+++ b/dbus/dbus-transport.h
@@ -71,7 +71,7 @@ void _dbus_transport_set_max_received_unix_fds(DBusTransport
long _dbus_transport_get_max_received_unix_fds(DBusTransport *transport);
dbus_bool_t _dbus_transport_get_socket_fd (DBusTransport *transport,
- int *fd_p);
+ DBusSocket *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,
@@ -87,6 +87,9 @@ void _dbus_transport_set_unix_user_function (DBusTransport
DBusFreeFunction *old_free_data_function);
dbus_bool_t _dbus_transport_get_windows_user (DBusTransport *transport,
char **windows_sid_p);
+dbus_bool_t _dbus_transport_get_linux_security_label (DBusTransport *transport,
+ char **label_p);
+
void _dbus_transport_set_windows_user_function (DBusTransport *transport,
DBusAllowWindowsUserFunction function,
void *data,
diff --git a/dbus/dbus-userdb.h b/dbus/dbus-userdb.h
index d6b72d8c..53fc90b5 100644
--- a/dbus/dbus-userdb.h
+++ b/dbus/dbus-userdb.h
@@ -56,6 +56,7 @@ 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_PRIVATE_EXPORT
dbus_bool_t _dbus_user_database_get_uid (DBusUserDatabase *db,
dbus_uid_t uid,
const DBusUserInfo **info,
@@ -64,6 +65,7 @@ dbus_bool_t _dbus_user_database_get_gid (DBusUserDatabase *db,
dbus_gid_t gid,
const DBusGroupInfo **info,
DBusError *error);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_user_database_get_username (DBusUserDatabase *db,
const DBusString *username,
const DBusUserInfo **info,
@@ -73,20 +75,27 @@ dbus_bool_t _dbus_user_database_get_groupname (DBusUserDatabase *db,
const DBusGroupInfo **info,
DBusError *error);
+DBUS_PRIVATE_EXPORT
DBusUserInfo* _dbus_user_database_lookup (DBusUserDatabase *db,
dbus_uid_t uid,
const DBusString *username,
DBusError *error);
+DBUS_PRIVATE_EXPORT
DBusGroupInfo* _dbus_user_database_lookup_group (DBusUserDatabase *db,
dbus_gid_t gid,
const DBusString *groupname,
DBusError *error);
+DBUS_PRIVATE_EXPORT
void _dbus_user_info_free_allocated (DBusUserInfo *info);
+DBUS_PRIVATE_EXPORT
void _dbus_group_info_free_allocated (DBusGroupInfo *info);
#endif /* DBUS_USERDB_INCLUDES_PRIVATE */
+DBUS_PRIVATE_EXPORT
DBusUserDatabase* _dbus_user_database_get_system (void);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_user_database_lock_system (void) _DBUS_GNUC_WARN_UNUSED_RESULT;
+DBUS_PRIVATE_EXPORT
void _dbus_user_database_unlock_system (void);
void _dbus_user_database_flush_system (void);
@@ -94,6 +103,7 @@ 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_PRIVATE_EXPORT
dbus_bool_t _dbus_get_user_id_and_primary_group (const DBusString *username,
dbus_uid_t *uid_p,
dbus_gid_t *gid_p);
@@ -102,13 +112,17 @@ dbus_bool_t _dbus_credentials_from_uid (dbus_uid_t user_id,
dbus_bool_t _dbus_groups_from_uid (dbus_uid_t uid,
dbus_gid_t **group_ids,
int *n_group_ids);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_is_console_user (dbus_uid_t uid,
DBusError *error);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_is_a_number (const DBusString *str,
unsigned long *num);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_username_from_current_process (const DBusString **username);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_homedir_from_current_process (const DBusString **homedir);
dbus_bool_t _dbus_homedir_from_username (const DBusString *username,
DBusString *homedir);
diff --git a/dbus/dbus-uuidgen.c b/dbus/dbus-uuidgen.c
index 6d7c0aec..b4041633 100644
--- a/dbus/dbus-uuidgen.c
+++ b/dbus/dbus-uuidgen.c
@@ -111,20 +111,20 @@ dbus_internal_do_not_use_get_uuid (const char *filename,
}
/**
- * 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
+ * @param error location to store reason for failure
+ * @returns #TRUE on success
*/
dbus_bool_t
-dbus_internal_do_not_use_create_uuid (char **uuid_p)
+_dbus_create_uuid (char **uuid_p,
+ DBusError *error)
{
DBusGUID uuid;
- _dbus_generate_uuid (&uuid);
- return return_uuid (&uuid, uuid_p, NULL);
+ if (!_dbus_generate_uuid (&uuid, error))
+ return FALSE;
+
+ return return_uuid (&uuid, uuid_p, error);
}
/** @} */
diff --git a/dbus/dbus-uuidgen.h b/dbus/dbus-uuidgen.h
index 9c1b8595..5e4a948c 100644
--- a/dbus/dbus-uuidgen.h
+++ b/dbus/dbus-uuidgen.h
@@ -32,6 +32,7 @@
DBUS_BEGIN_DECLS
+DBUS_PRIVATE_EXPORT
dbus_bool_t dbus_internal_do_not_use_get_uuid (const char *filename,
char **uuid_p,
dbus_bool_t create_if_not_found,
@@ -39,8 +40,9 @@ dbus_bool_t dbus_internal_do_not_use_get_uuid (const char *filename,
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_PRIVATE_EXPORT
+dbus_bool_t _dbus_create_uuid (char **uuid_p,
+ DBusError *error);
DBUS_END_DECLS
diff --git a/dbus/dbus-watch.c b/dbus/dbus-watch.c
index 76a5d641..093f1937 100644
--- a/dbus/dbus-watch.c
+++ b/dbus/dbus-watch.c
@@ -40,7 +40,7 @@
struct DBusWatch
{
int refcount; /**< Reference count */
- int fd; /**< File descriptor. */
+ DBusPollable fd; /**< File descriptor. */
unsigned int flags; /**< Conditions to watch. */
DBusWatchHandler handler; /**< Watch handler. */
@@ -85,7 +85,7 @@ _dbus_watch_set_oom_last_time (DBusWatch *watch,
* @returns the new DBusWatch object.
*/
DBusWatch*
-_dbus_watch_new (int fd,
+_dbus_watch_new (DBusPollable fd,
unsigned int flags,
dbus_bool_t enabled,
DBusWatchHandler handler,
@@ -143,7 +143,7 @@ _dbus_watch_unref (DBusWatch *watch)
watch->refcount -= 1;
if (watch->refcount == 0)
{
- if (watch->fd != -1)
+ if (_dbus_pollable_is_valid (watch->fd))
_dbus_warn ("this watch should have been invalidated");
dbus_watch_set_data (watch, NULL, NULL); /* call free_data_function */
@@ -168,7 +168,7 @@ _dbus_watch_unref (DBusWatch *watch)
void
_dbus_watch_invalidate (DBusWatch *watch)
{
- watch->fd = -1;
+ _dbus_pollable_invalidate (&watch->fd);
watch->flags = 0;
}
@@ -310,10 +310,13 @@ _dbus_watch_list_set_functions (DBusWatchList *watch_list,
{
DBusList *next = _dbus_list_get_next_link (&watch_list->watches,
link);
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+ DBusWatch *watch = link->data;
- _dbus_verbose ("Adding a %s watch on fd %d using newly-set add watch function\n",
+ _dbus_verbose ("Adding a %s watch on fd %" DBUS_POLLABLE_FORMAT " using newly-set add watch function\n",
watch_flags_to_string (dbus_watch_get_flags (link->data)),
- dbus_watch_get_socket (link->data));
+ _dbus_pollable_printable (watch->fd));
+#endif
if (!(* add_function) (link->data, data))
{
@@ -325,9 +328,12 @@ _dbus_watch_list_set_functions (DBusWatchList *watch_list,
{
DBusList *next = _dbus_list_get_next_link (&watch_list->watches,
link2);
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+ DBusWatch *watch2 = link2->data;
- _dbus_verbose ("Removing watch on fd %d using newly-set remove function because initial add failed\n",
- dbus_watch_get_socket (link2->data));
+ _dbus_verbose ("Removing watch on fd %" DBUS_POLLABLE_FORMAT " using newly-set remove function because initial add failed\n",
+ _dbus_pollable_printable (watch2->fd));
+#endif
(* remove_function) (link2->data, data);
@@ -383,8 +389,8 @@ _dbus_watch_list_add_watch (DBusWatchList *watch_list,
if (watch_list->add_watch_function != NULL)
{
- _dbus_verbose ("Adding watch on fd %d\n",
- dbus_watch_get_socket (watch));
+ _dbus_verbose ("Adding watch on fd %" DBUS_POLLABLE_FORMAT "\n",
+ _dbus_pollable_printable (watch->fd));
if (!(* watch_list->add_watch_function) (watch,
watch_list->watch_data))
@@ -414,8 +420,8 @@ _dbus_watch_list_remove_watch (DBusWatchList *watch_list,
if (watch_list->remove_watch_function != NULL)
{
- _dbus_verbose ("Removing watch on fd %d\n",
- dbus_watch_get_socket (watch));
+ _dbus_verbose ("Removing watch on fd %" DBUS_POLLABLE_FORMAT "\n",
+ _dbus_pollable_printable (watch->fd));
(* watch_list->remove_watch_function) (watch,
watch_list->watch_data);
@@ -446,8 +452,10 @@ _dbus_watch_list_toggle_watch (DBusWatchList *watch_list,
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);
+ _dbus_verbose ("Toggling watch %p on fd %" DBUS_POLLABLE_FORMAT " to %d\n",
+ watch,
+ _dbus_pollable_printable (watch->fd),
+ watch->enabled);
(* watch_list->watch_toggled_function) (watch,
watch_list->watch_data);
@@ -587,6 +595,34 @@ dbus_watch_get_socket (DBusWatch *watch)
{
_dbus_return_val_if_fail (watch != NULL, -1);
+#ifdef DBUS_UNIX
+ return watch->fd;
+#else
+ return _dbus_socket_get_int (watch->fd);
+#endif
+}
+
+DBusSocket
+_dbus_watch_get_socket (DBusWatch *watch)
+{
+ DBusSocket s;
+
+ _dbus_assert (watch != NULL);
+
+#ifdef DBUS_UNIX
+ s.fd = watch->fd;
+#else
+ s = watch->fd;
+#endif
+
+ return s;
+}
+
+DBusPollable
+_dbus_watch_get_pollable (DBusWatch *watch)
+{
+ _dbus_assert (watch != NULL);
+
return watch->fd;
}
@@ -645,8 +681,8 @@ dbus_watch_set_data (DBusWatch *watch,
{
_dbus_return_if_fail (watch != NULL);
- _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n",
- dbus_watch_get_socket (watch),
+ _dbus_verbose ("Setting watch fd %" DBUS_POLLABLE_FORMAT " data to data = %p function = %p from data = %p function = %p\n",
+ _dbus_pollable_printable (watch->fd),
data, free_data_function, watch->data, watch->free_data_function);
if (watch->free_data_function != NULL)
@@ -701,21 +737,21 @@ dbus_watch_handle (DBusWatch *watch,
_dbus_return_val_if_fail (watch != NULL, FALSE);
#ifndef DBUS_DISABLE_CHECKS
- if (watch->fd < 0 || watch->flags == 0)
+ if (!_dbus_pollable_is_valid (watch->fd) || watch->flags == 0)
{
_dbus_warn_check_failed ("Watch is invalid, it should have been removed\n");
return TRUE;
}
#endif
- _dbus_return_val_if_fail (watch->fd >= 0 /* fails if watch was removed */, TRUE);
+ _dbus_return_val_if_fail (_dbus_pollable_is_valid (watch->fd) /* 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);
+ _dbus_verbose ("After sanitization, watch flags on fd %" DBUS_POLLABLE_FORMAT " were 0\n",
+ _dbus_pollable_printable (watch->fd));
return TRUE;
}
else
diff --git a/dbus/dbus-watch.h b/dbus/dbus-watch.h
index 321740ed..8d8bbf2b 100644
--- a/dbus/dbus-watch.h
+++ b/dbus/dbus-watch.h
@@ -44,14 +44,18 @@ typedef dbus_bool_t (* DBusWatchHandler) (DBusWatch *watch,
unsigned int flags,
void *data);
-DBusWatch* _dbus_watch_new (int fd,
+DBUS_PRIVATE_EXPORT
+DBusWatch* _dbus_watch_new (DBusPollable fd,
unsigned int flags,
dbus_bool_t enabled,
DBusWatchHandler handler,
void *data,
DBusFreeFunction free_data_function);
+DBUS_PRIVATE_EXPORT
DBusWatch* _dbus_watch_ref (DBusWatch *watch);
+DBUS_PRIVATE_EXPORT
void _dbus_watch_unref (DBusWatch *watch);
+DBUS_PRIVATE_EXPORT
void _dbus_watch_invalidate (DBusWatch *watch);
void _dbus_watch_sanitize_condition (DBusWatch *watch,
unsigned int *condition);
@@ -61,16 +65,21 @@ void _dbus_watch_set_handler (DBusWatch *watch,
DBusFreeFunction free_data_function);
+DBUS_PRIVATE_EXPORT
DBusWatchList* _dbus_watch_list_new (void);
+DBUS_PRIVATE_EXPORT
void _dbus_watch_list_free (DBusWatchList *watch_list);
+DBUS_PRIVATE_EXPORT
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_PRIVATE_EXPORT
dbus_bool_t _dbus_watch_list_add_watch (DBusWatchList *watch_list,
DBusWatch *watch);
+DBUS_PRIVATE_EXPORT
void _dbus_watch_list_remove_watch (DBusWatchList *watch_list,
DBusWatch *watch);
void _dbus_watch_list_toggle_watch (DBusWatchList *watch_list,
@@ -80,10 +89,16 @@ void _dbus_watch_list_toggle_all_watches (DBusWatchList *watch_li
dbus_bool_t enabled);
dbus_bool_t _dbus_watch_get_enabled (DBusWatch *watch);
+DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_watch_get_oom_last_time (DBusWatch *watch);
+DBUS_PRIVATE_EXPORT
void _dbus_watch_set_oom_last_time (DBusWatch *watch,
dbus_bool_t oom);
+DBusSocket _dbus_watch_get_socket (DBusWatch *watch);
+DBUS_PRIVATE_EXPORT
+DBusPollable _dbus_watch_get_pollable (DBusWatch *watch);
+
/** @} */
DBUS_END_DECLS
diff --git a/dbus/sd-daemon.c b/dbus/sd-daemon.c
deleted file mode 100644
index 485b3010..00000000
--- a/dbus/sd-daemon.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- Copyright 2010 Lennart Poettering
-
- 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 AUTHORS OR COPYRIGHT HOLDERS
- BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-***/
-
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE
-#endif
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <limits.h>
-
-#if defined(__linux__) && !defined(SD_DAEMON_DISABLE_MQ)
-# include <mqueue.h>
-#endif
-
-#include "sd-daemon.h"
-
-#if (__GNUC__ >= 4)
-# ifdef SD_EXPORT_SYMBOLS
-/* Export symbols */
-# define _sd_export_ __attribute__ ((visibility("default")))
-# else
-/* Don't export the symbols */
-# define _sd_export_ __attribute__ ((visibility("hidden")))
-# endif
-#else
-# define _sd_export_
-#endif
-
-_sd_export_ int sd_listen_fds(int unset_environment) {
-
-#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
- return 0;
-#else
- int r, fd;
- const char *e;
- char *p = NULL;
- unsigned long l;
-
- e = getenv("LISTEN_PID");
- if (!e) {
- r = 0;
- goto finish;
- }
-
- errno = 0;
- l = strtoul(e, &p, 10);
-
- if (errno > 0) {
- r = -errno;
- goto finish;
- }
-
- if (!p || p == e || *p || l <= 0) {
- r = -EINVAL;
- goto finish;
- }
-
- /* Is this for us? */
- if (getpid() != (pid_t) l) {
- r = 0;
- goto finish;
- }
-
- e = getenv("LISTEN_FDS");
- if (!e) {
- r = 0;
- goto finish;
- }
-
- errno = 0;
- l = strtoul(e, &p, 10);
-
- if (errno > 0) {
- r = -errno;
- goto finish;
- }
-
- if (!p || p == e || *p) {
- r = -EINVAL;
- goto finish;
- }
-
- for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) {
- int flags;
-
- flags = fcntl(fd, F_GETFD);
- if (flags < 0) {
- r = -errno;
- goto finish;
- }
-
- if (flags & FD_CLOEXEC)
- continue;
-
- if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
- r = -errno;
- goto finish;
- }
- }
-
- r = (int) l;
-
-finish:
- if (unset_environment) {
- unsetenv("LISTEN_PID");
- unsetenv("LISTEN_FDS");
- }
-
- return r;
-#endif
-}
-
-_sd_export_ int sd_is_fifo(int fd, const char *path) {
- struct stat st_fd;
-
- if (fd < 0)
- return -EINVAL;
-
- if (fstat(fd, &st_fd) < 0)
- return -errno;
-
- if (!S_ISFIFO(st_fd.st_mode))
- return 0;
-
- if (path) {
- struct stat st_path;
-
- if (stat(path, &st_path) < 0) {
-
- if (errno == ENOENT || errno == ENOTDIR)
- return 0;
-
- return -errno;
- }
-
- return
- st_path.st_dev == st_fd.st_dev &&
- st_path.st_ino == st_fd.st_ino;
- }
-
- return 1;
-}
-
-_sd_export_ int sd_is_special(int fd, const char *path) {
- struct stat st_fd;
-
- if (fd < 0)
- return -EINVAL;
-
- if (fstat(fd, &st_fd) < 0)
- return -errno;
-
- if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
- return 0;
-
- if (path) {
- struct stat st_path;
-
- if (stat(path, &st_path) < 0) {
-
- if (errno == ENOENT || errno == ENOTDIR)
- return 0;
-
- return -errno;
- }
-
- if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
- return
- st_path.st_dev == st_fd.st_dev &&
- st_path.st_ino == st_fd.st_ino;
- else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
- return st_path.st_rdev == st_fd.st_rdev;
- else
- return 0;
- }
-
- return 1;
-}
-
-static int sd_is_socket_internal(int fd, int type, int listening) {
- struct stat st_fd;
-
- if (fd < 0 || type < 0)
- return -EINVAL;
-
- if (fstat(fd, &st_fd) < 0)
- return -errno;
-
- if (!S_ISSOCK(st_fd.st_mode))
- return 0;
-
- if (type != 0) {
- int other_type = 0;
- socklen_t l = sizeof(other_type);
-
- if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
- return -errno;
-
- if (l != sizeof(other_type))
- return -EINVAL;
-
- if (other_type != type)
- return 0;
- }
-
- if (listening >= 0) {
- int accepting = 0;
- socklen_t l = sizeof(accepting);
-
- if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
- return -errno;
-
- if (l != sizeof(accepting))
- return -EINVAL;
-
- if (!accepting != !listening)
- return 0;
- }
-
- return 1;
-}
-
-union sockaddr_union {
- struct sockaddr sa;
- struct sockaddr_in in4;
- struct sockaddr_in6 in6;
- struct sockaddr_un un;
- struct sockaddr_storage storage;
-};
-
-_sd_export_ int sd_is_socket(int fd, int family, int type, int listening) {
- int r;
-
- if (family < 0)
- return -EINVAL;
-
- r = sd_is_socket_internal(fd, type, listening);
- if (r <= 0)
- return r;
-
- if (family > 0) {
- union sockaddr_union sockaddr = {};
- socklen_t l = sizeof(sockaddr);
-
- if (getsockname(fd, &sockaddr.sa, &l) < 0)
- return -errno;
-
- if (l < sizeof(sa_family_t))
- return -EINVAL;
-
- return sockaddr.sa.sa_family == family;
- }
-
- return 1;
-}
-
-_sd_export_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
- union sockaddr_union sockaddr = {};
- socklen_t l = sizeof(sockaddr);
- int r;
-
- if (family != 0 && family != AF_INET && family != AF_INET6)
- return -EINVAL;
-
- r = sd_is_socket_internal(fd, type, listening);
- if (r <= 0)
- return r;
-
- if (getsockname(fd, &sockaddr.sa, &l) < 0)
- return -errno;
-
- if (l < sizeof(sa_family_t))
- return -EINVAL;
-
- if (sockaddr.sa.sa_family != AF_INET &&
- sockaddr.sa.sa_family != AF_INET6)
- return 0;
-
- if (family > 0)
- if (sockaddr.sa.sa_family != family)
- return 0;
-
- if (port > 0) {
- if (sockaddr.sa.sa_family == AF_INET) {
- if (l < sizeof(struct sockaddr_in))
- return -EINVAL;
-
- return htons(port) == sockaddr.in4.sin_port;
- } else {
- if (l < sizeof(struct sockaddr_in6))
- return -EINVAL;
-
- return htons(port) == sockaddr.in6.sin6_port;
- }
- }
-
- return 1;
-}
-
-_sd_export_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
- union sockaddr_union sockaddr = {};
- socklen_t l = sizeof(sockaddr);
- int r;
-
- r = sd_is_socket_internal(fd, type, listening);
- if (r <= 0)
- return r;
-
- if (getsockname(fd, &sockaddr.sa, &l) < 0)
- return -errno;
-
- if (l < sizeof(sa_family_t))
- return -EINVAL;
-
- if (sockaddr.sa.sa_family != AF_UNIX)
- return 0;
-
- if (path) {
- if (length == 0)
- length = strlen(path);
-
- if (length == 0)
- /* Unnamed socket */
- return l == offsetof(struct sockaddr_un, sun_path);
-
- if (path[0])
- /* Normal path socket */
- return
- (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
- memcmp(path, sockaddr.un.sun_path, length+1) == 0;
- else
- /* Abstract namespace socket */
- return
- (l == offsetof(struct sockaddr_un, sun_path) + length) &&
- memcmp(path, sockaddr.un.sun_path, length) == 0;
- }
-
- return 1;
-}
-
-_sd_export_ int sd_is_mq(int fd, const char *path) {
-#if !defined(__linux__) || defined(SD_DAEMON_DISABLE_MQ)
- return 0;
-#else
- struct mq_attr attr;
-
- if (fd < 0)
- return -EINVAL;
-
- if (mq_getattr(fd, &attr) < 0)
- return -errno;
-
- if (path) {
- char fpath[PATH_MAX];
- struct stat a, b;
-
- if (path[0] != '/')
- return -EINVAL;
-
- if (fstat(fd, &a) < 0)
- return -errno;
-
- strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
- fpath[sizeof(fpath)-1] = 0;
-
- if (stat(fpath, &b) < 0)
- return -errno;
-
- if (a.st_dev != b.st_dev ||
- a.st_ino != b.st_ino)
- return 0;
- }
-
- return 1;
-#endif
-}
-
-_sd_export_ int sd_notify(int unset_environment, const char *state) {
-#if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC)
- return 0;
-#else
- int fd = -1, r;
- struct msghdr msghdr;
- struct iovec iovec;
- union sockaddr_union sockaddr;
- const char *e;
-
- if (!state) {
- r = -EINVAL;
- goto finish;
- }
-
- e = getenv("NOTIFY_SOCKET");
- if (!e)
- return 0;
-
- /* Must be an abstract socket, or an absolute path */
- if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
- r = -EINVAL;
- goto finish;
- }
-
- fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
- if (fd < 0) {
- r = -errno;
- goto finish;
- }
-
- memset(&sockaddr, 0, sizeof(sockaddr));
- sockaddr.sa.sa_family = AF_UNIX;
- strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
-
- if (sockaddr.un.sun_path[0] == '@')
- sockaddr.un.sun_path[0] = 0;
-
- memset(&iovec, 0, sizeof(iovec));
- iovec.iov_base = (char*) state;
- iovec.iov_len = strlen(state);
-
- memset(&msghdr, 0, sizeof(msghdr));
- msghdr.msg_name = &sockaddr;
- msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
-
- if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
- msghdr.msg_namelen = sizeof(struct sockaddr_un);
-
- msghdr.msg_iov = &iovec;
- msghdr.msg_iovlen = 1;
-
- if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
- r = -errno;
- goto finish;
- }
-
- r = 1;
-
-finish:
- if (unset_environment)
- unsetenv("NOTIFY_SOCKET");
-
- if (fd >= 0)
- close(fd);
-
- return r;
-#endif
-}
-
-_sd_export_ int sd_notifyf(int unset_environment, const char *format, ...) {
-#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
- return 0;
-#else
- va_list ap;
- char *p = NULL;
- int r;
-
- va_start(ap, format);
- r = vasprintf(&p, format, ap);
- va_end(ap);
-
- if (r < 0 || !p)
- return -ENOMEM;
-
- r = sd_notify(unset_environment, p);
- free(p);
-
- return r;
-#endif
-}
-
-_sd_export_ int sd_booted(void) {
-#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
- return 0;
-#else
- struct stat st;
-
- /* We test whether the runtime unit file directory has been
- * created. This takes place in mount-setup.c, so is
- * guaranteed to happen very early during boot. */
-
- if (lstat("/run/systemd/system/", &st) < 0)
- return 0;
-
- return !!S_ISDIR(st.st_mode);
-#endif
-}
diff --git a/dbus/sd-daemon.h b/dbus/sd-daemon.h
deleted file mode 100644
index fb7456d5..00000000
--- a/dbus/sd-daemon.h
+++ /dev/null
@@ -1,282 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foosddaemonhfoo
-#define foosddaemonhfoo
-
-/***
- Copyright 2010 Lennart Poettering
-
- 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 AUTHORS OR COPYRIGHT HOLDERS
- BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-***/
-
-#include <sys/types.h>
-#include <inttypes.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- Reference implementation of a few systemd related interfaces for
- writing daemons. These interfaces are trivial to implement. To
- simplify porting we provide this reference implementation.
- Applications are welcome to reimplement the algorithms described
- here if they do not want to include these two source files.
-
- The following functionality is provided:
-
- - Support for logging with log levels on stderr
- - File descriptor passing for socket-based activation
- - Daemon startup and status notification
- - Detection of systemd boots
-
- You may compile this with -DDISABLE_SYSTEMD to disable systemd
- support. This makes all those calls NOPs that are directly related to
- systemd (i.e. only sd_is_xxx() will stay useful).
-
- Since this is drop-in code we don't want any of our symbols to be
- exported in any case. Hence we declare hidden visibility for all of
- them.
-
- You may find an up-to-date version of these source files online:
-
- http://cgit.freedesktop.org/systemd/systemd/plain/src/systemd/sd-daemon.h
- http://cgit.freedesktop.org/systemd/systemd/plain/src/libsystemd-daemon/sd-daemon.c
-
- This should compile on non-Linux systems, too, but with the
- exception of the sd_is_xxx() calls all functions will become NOPs.
-
- See sd-daemon(3) for more information.
-*/
-
-#ifndef _sd_printf_attr_
-#if __GNUC__ >= 4
-#define _sd_printf_attr_(a,b) __attribute__ ((format (printf, a, b)))
-#else
-#define _sd_printf_attr_(a,b)
-#endif
-#endif
-
-/*
- Log levels for usage on stderr:
-
- fprintf(stderr, SD_NOTICE "Hello World!\n");
-
- This is similar to printk() usage in the kernel.
-*/
-#define SD_EMERG "<0>" /* system is unusable */
-#define SD_ALERT "<1>" /* action must be taken immediately */
-#define SD_CRIT "<2>" /* critical conditions */
-#define SD_ERR "<3>" /* error conditions */
-#define SD_WARNING "<4>" /* warning conditions */
-#define SD_NOTICE "<5>" /* normal but significant condition */
-#define SD_INFO "<6>" /* informational */
-#define SD_DEBUG "<7>" /* debug-level messages */
-
-/* The first passed file descriptor is fd 3 */
-#define SD_LISTEN_FDS_START 3
-
-/*
- Returns how many file descriptors have been passed, or a negative
- errno code on failure. Optionally, removes the $LISTEN_FDS and
- $LISTEN_PID file descriptors from the environment (recommended, but
- problematic in threaded environments). If r is the return value of
- this function you'll find the file descriptors passed as fds
- SD_LISTEN_FDS_START to SD_LISTEN_FDS_START+r-1. Returns a negative
- errno style error code on failure. This function call ensures that
- the FD_CLOEXEC flag is set for the passed file descriptors, to make
- sure they are not passed on to child processes. If FD_CLOEXEC shall
- not be set, the caller needs to unset it after this call for all file
- descriptors that are used.
-
- See sd_listen_fds(3) for more information.
-*/
-int sd_listen_fds(int unset_environment);
-
-/*
- Helper call for identifying a passed file descriptor. Returns 1 if
- the file descriptor is a FIFO in the file system stored under the
- specified path, 0 otherwise. If path is NULL a path name check will
- not be done and the call only verifies if the file descriptor
- refers to a FIFO. Returns a negative errno style error code on
- failure.
-
- See sd_is_fifo(3) for more information.
-*/
-int sd_is_fifo(int fd, const char *path);
-
-/*
- Helper call for identifying a passed file descriptor. Returns 1 if
- the file descriptor is a special character device on the file
- system stored under the specified path, 0 otherwise.
- If path is NULL a path name check will not be done and the call
- only verifies if the file descriptor refers to a special character.
- Returns a negative errno style error code on failure.
-
- See sd_is_special(3) for more information.
-*/
-int sd_is_special(int fd, const char *path);
-
-/*
- Helper call for identifying a passed file descriptor. Returns 1 if
- the file descriptor is a socket of the specified family (AF_INET,
- ...) and type (SOCK_DGRAM, SOCK_STREAM, ...), 0 otherwise. If
- family is 0 a socket family check will not be done. If type is 0 a
- socket type check will not be done and the call only verifies if
- the file descriptor refers to a socket. If listening is > 0 it is
- verified that the socket is in listening mode. (i.e. listen() has
- been called) If listening is == 0 it is verified that the socket is
- not in listening mode. If listening is < 0 no listening mode check
- is done. Returns a negative errno style error code on failure.
-
- See sd_is_socket(3) for more information.
-*/
-int sd_is_socket(int fd, int family, int type, int listening);
-
-/*
- Helper call for identifying a passed file descriptor. Returns 1 if
- the file descriptor is an Internet socket, of the specified family
- (either AF_INET or AF_INET6) and the specified type (SOCK_DGRAM,
- SOCK_STREAM, ...), 0 otherwise. If version is 0 a protocol version
- check is not done. If type is 0 a socket type check will not be
- done. If port is 0 a socket port check will not be done. The
- listening flag is used the same way as in sd_is_socket(). Returns a
- negative errno style error code on failure.
-
- See sd_is_socket_inet(3) for more information.
-*/
-int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port);
-
-/*
- Helper call for identifying a passed file descriptor. Returns 1 if
- the file descriptor is an AF_UNIX socket of the specified type
- (SOCK_DGRAM, SOCK_STREAM, ...) and path, 0 otherwise. If type is 0
- a socket type check will not be done. If path is NULL a socket path
- check will not be done. For normal AF_UNIX sockets set length to
- 0. For abstract namespace sockets set length to the length of the
- socket name (including the initial 0 byte), and pass the full
- socket path in path (including the initial 0 byte). The listening
- flag is used the same way as in sd_is_socket(). Returns a negative
- errno style error code on failure.
-
- See sd_is_socket_unix(3) for more information.
-*/
-int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length);
-
-/*
- Helper call for identifying a passed file descriptor. Returns 1 if
- the file descriptor is a POSIX Message Queue of the specified name,
- 0 otherwise. If path is NULL a message queue name check is not
- done. Returns a negative errno style error code on failure.
-*/
-int sd_is_mq(int fd, const char *path);
-
-/*
- Informs systemd about changed daemon state. This takes a number of
- newline separated environment-style variable assignments in a
- string. The following variables are known:
-
- READY=1 Tells systemd that daemon startup is finished (only
- relevant for services of Type=notify). The passed
- argument is a boolean "1" or "0". Since there is
- little value in signaling non-readiness the only
- value daemons should send is "READY=1".
-
- STATUS=... Passes a single-line status string back to systemd
- that describes the daemon state. This is free-from
- and can be used for various purposes: general state
- feedback, fsck-like programs could pass completion
- percentages and failing programs could pass a human
- readable error message. Example: "STATUS=Completed
- 66% of file system check..."
-
- ERRNO=... If a daemon fails, the errno-style error code,
- formatted as string. Example: "ERRNO=2" for ENOENT.
-
- BUSERROR=... If a daemon fails, the D-Bus error-style error
- code. Example: "BUSERROR=org.freedesktop.DBus.Error.TimedOut"
-
- MAINPID=... The main pid of a daemon, in case systemd did not
- fork off the process itself. Example: "MAINPID=4711"
-
- WATCHDOG=1 Tells systemd to update the watchdog timestamp.
- Services using this feature should do this in
- regular intervals. A watchdog framework can use the
- timestamps to detect failed services.
-
- Daemons can choose to send additional variables. However, it is
- recommended to prefix variable names not listed above with X_.
-
- Returns a negative errno-style error code on failure. Returns > 0
- if systemd could be notified, 0 if it couldn't possibly because
- systemd is not running.
-
- Example: When a daemon finished starting up, it could issue this
- call to notify systemd about it:
-
- sd_notify(0, "READY=1");
-
- See sd_notifyf() for more complete examples.
-
- See sd_notify(3) for more information.
-*/
-int sd_notify(int unset_environment, const char *state);
-
-/*
- Similar to sd_notify() but takes a format string.
-
- Example 1: A daemon could send the following after initialization:
-
- sd_notifyf(0, "READY=1\n"
- "STATUS=Processing requests...\n"
- "MAINPID=%lu",
- (unsigned long) getpid());
-
- Example 2: A daemon could send the following shortly before
- exiting, on failure:
-
- sd_notifyf(0, "STATUS=Failed to start up: %s\n"
- "ERRNO=%i",
- strerror(errno),
- errno);
-
- See sd_notifyf(3) for more information.
-*/
-int sd_notifyf(int unset_environment, const char *format, ...) _sd_printf_attr_(2,3);
-
-/*
- Returns > 0 if the system was booted with systemd. Returns < 0 on
- error. Returns 0 if the system was not booted with systemd. Note
- that all of the functions above handle non-systemd boots just
- fine. You should NOT protect them with a call to this function. Also
- note that this function checks whether the system, not the user
- session is controlled by systemd. However the functions above work
- for both user and system services.
-
- See sd_booted(3) for more information.
-*/
-int sd_booted(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/doc/.gitignore b/doc/.gitignore
index 708fe36f..e1ccbc8d 100644
--- a/doc/.gitignore
+++ b/doc/.gitignore
@@ -17,3 +17,12 @@ dbus-faq.html
dbus-docs
dbus-docs.tar.gz
doxygen.stamp
+dbus-api-design.page
+dbus-api-design.html
+jquery.js
+jquery.syntax.brush.html.js
+jquery.syntax.core.js
+jquery.syntax.js
+jquery.syntax.layout.yelp.js
+yelp.js
+C.css
diff --git a/doc/Makefile.am b/doc/Makefile.am
index b9a4c106..8bc85c53 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -7,6 +7,8 @@ man_pages = \
dbus-monitor.1 \
dbus-run-session.1 \
dbus-send.1 \
+ dbus-test-tool.1 \
+ dbus-update-activation-environment.1 \
dbus-uuidgen.1 \
$(NULL)
@@ -30,6 +32,7 @@ STATIC_DOCS = \
dbus-specification.xml \
dbus-test-plan.xml \
dbus-tutorial.xml \
+ dbus-api-design.duck \
dcop-howto.txt \
introspect.xsl \
$(DTDS)
@@ -50,8 +53,24 @@ STATIC_HTML = \
diagram.svg \
$(NULL)
+# Static HTML helper files generated by yelp-build.
+YELP_STATIC_HTML = \
+ yelp.js \
+ C.css \
+ jquery.js \
+ jquery.syntax.js \
+ jquery.syntax.brush.html.js \
+ jquery.syntax.core.js \
+ jquery.syntax.layout.yelp.js \
+ $(NULL)
+
dist_html_DATA += $(STATIC_HTML)
+# Content HTML files generated by yelp-build.
+YELP_HTML = \
+ dbus-api-design.html \
+ $(NULL)
+
XMLTO_HTML = \
dbus-faq.html \
dbus-specification.html \
@@ -84,6 +103,16 @@ dbus.devhelp: $(srcdir)/doxygen_to_devhelp.xsl doxygen.stamp
$(XSLTPROC) -o $@ $< api/xml/index.xml
endif
+if DBUS_DUCKTYPE_DOCS_ENABLED
+html_DATA += $(YELP_HTML) $(YELP_STATIC_HTML)
+
+%.page: %.duck
+ $(DUCKTYPE) -o $@ $<
+%.html: %.page
+ $(YELP_BUILD) html $<
+$(YELP_STATIC_HTML): $(YELP_HTML)
+endif
+
# this assumes CREATE_SUBDIRS isn't set to YES in Doxyfile
# (which it isn't currently)
install-data-local:: doxygen.stamp
@@ -112,13 +141,15 @@ BONUS_FILES = \
$(top_srcdir)/COPYING \
$(top_srcdir)/ChangeLog
-dbus-docs: $(STATIC_DOCS) $(MAN_XML_FILES) $(dist_doc_DATA) $(dist_html_DATA) $(MAN_HTML_FILES) $(BONUS_FILES) doxygen.stamp $(XMLTO_HTML)
+dbus-docs: $(STATIC_DOCS) $(MAN_XML_FILES) $(dist_doc_DATA) $(dist_html_DATA) $(MAN_HTML_FILES) $(BONUS_FILES) doxygen.stamp $(XMLTO_HTML) $(YELP_HTML) $(YELP_STATIC_HTML)
$(AM_V_at)rm -rf $@ $@.tmp
$(AM_V_GEN)$(MKDIR_P) $@.tmp/api
$(AM_V_at)cd $(srcdir) && cp $(STATIC_DOCS) @abs_builddir@/$@.tmp
$(AM_V_at)cd $(srcdir) && cp $(dist_doc_DATA) @abs_builddir@/$@.tmp
$(AM_V_at)cd $(srcdir) && cp $(STATIC_HTML) @abs_builddir@/$@.tmp
$(AM_V_at)cp $(XMLTO_HTML) @abs_builddir@/$@.tmp
+ $(AM_V_at)cp $(YELP_HTML) @abs_builddir@/$@.tmp
+ $(AM_V_at)cp $(YELP_STATIC_HTML) @abs_builddir@/$@.tmp
$(AM_V_at)cp $(MAN_HTML_FILES) @abs_builddir@/$@.tmp
$(AM_V_at)cp $(MAN_XML_FILES) @abs_builddir@/$@.tmp
$(AM_V_at)cp $(BONUS_FILES) @abs_builddir@/$@.tmp
@@ -142,7 +173,7 @@ maintainer-upload-docs: dbus-docs.tar.gz dbus-docs
else
maintainer-upload-docs:
@echo "Can't upload documentation! Re-run configure with"
- @echo " --enable-doxygen-docs --enable-xml-docs"
+ @echo " --enable-doxygen-docs --enable-xml-docs --enable-ducktype-docs"
@echo "and ensure that man2html is installed."
@false
endif
@@ -151,6 +182,8 @@ CLEANFILES = \
$(man1_MANS) \
$(MAN_XML_FILES) \
$(XMLTO_HTML) \
+ $(YELP_HTML) \
+ $(YELP_STATIC_HTML) \
$(NULL)
clean-local:
diff --git a/doc/busconfig.dtd b/doc/busconfig.dtd
index 0cc519b4..8c5ac334 100644
--- a/doc/busconfig.dtd
+++ b/doc/busconfig.dtd
@@ -11,7 +11,8 @@
include |
policy |
limit |
- selinux)*>
+ selinux |
+ apparmor)*>
<!ELEMENT user (#PCDATA)>
<!ELEMENT listen (#PCDATA)>
@@ -63,3 +64,7 @@
<!ATTLIST associate
own CDATA #REQUIRED
context CDATA #REQUIRED>
+
+<!ELEMENT apparmor EMPTY>
+<!ATTLIST apparmor
+ mode (required|enabled|disabled) "enabled">
diff --git a/doc/dbus-api-design.duck b/doc/dbus-api-design.duck
new file mode 100644
index 00000000..be3ea9fd
--- /dev/null
+++ b/doc/dbus-api-design.duck
@@ -0,0 +1,888 @@
+= D-Bus API Design Guidelines
+@link[guide >index]
+@credit[type="author copyright"]
+ @name Philip Withnall
+ @email philip.withnall@collabora.co.uk
+ @years 2015
+@desc Guidelines for writing high quality D-Bus APIs
+@revision[date=2015-02-05 status=draft]
+
+[synopsis]
+ [title]
+ Summary
+
+ The most common use for D-Bus is in implementing a service which will be
+ consumed by multiple client programs, and hence all interfaces exported on the
+ bus form a public API. Designing a D-Bus API is like designing any other API:
+ there is a lot of flexibility, but there are design patterns to follow and
+ anti-patterns to avoid.
+
+ This guide aims to explain the best practices for writing D-Bus APIs. These
+ have been refined over several years of use of D-Bus in many projects.
+ Pointers will be given for implementing APIs using common D-Bus
+ libraries like
+ $link[>>https://developer.gnome.org/gio/stable/gdbus-convenience.html](GDBus),
+ but detailed implementation instructions are left to the libraries’
+ documentation. Note that you should $em(not) use dbus-glib to implement D-Bus
+ services as it is deprecated and unmaintained. Most services should also avoid
+ libdbus (dbus-1), which is a low-level library and is awkward to use
+ correctly: it is designed to be used via a language binding such as
+ $link[>>http://qt-project.org/doc/qt-4.8/qtdbus.html](QtDBus).
+
+ For documentation on D-Bus itself, see the
+ $link[>>http://dbus.freedesktop.org/doc/dbus-specification.html](D-Bus
+ specification).
+
+[links section]
+
+== APIs
+ [id="apis"]
+
+A D-Bus API is a specification of one or more interfaces, which will be
+implemented by objects exposed by a service on the bus. Typically an API is
+designed as a set of $link[>#interface-files](interface files), and the
+implementation of the service follows those files. Some projects, however,
+choose to define the API in the code for the service, and to export XML
+interface files from the running service
+$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-introspectable](using
+D-Bus introspection). Both are valid approaches.
+
+For simplicity, this document uses the XML descriptions of D-Bus interfaces as
+the canonical representation.
+
+== Interface files
+ [id="interface-files"]
+
+A D-Bus interface file is an XML file which describes one or more D-Bus
+interfaces, and is the best way of describing a D-Bus API in a machine
+readable way. The format is described in the
+$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format](D-Bus
+specification), and is supported by tools such as $cmd(gdbus-codegen).
+
+Interface files for public API should be installed to
+$code($var($$(datadir$))/dbus-1/interfaces) so that other services can load
+them. Private APIs should not be installed. There should be one file installed
+per D-Bus interface, named after the interface, containing a single top-level
+$code(<node>) element with a single $code(<interface>) beneath it. For example,
+interface $code(com.example.MyService1.Manager) would be described by file
+$file($var($$(datadir$))/dbus-1/interfaces/com.example.MyService1.Manager.xml):
+
+[listing]
+ [title]
+ Example D-Bus Interface XML
+ [desc]
+ A brief example interface XML document.
+ [code mime="application/xml"]
+ <!DOCTYPE node PUBLIC
+ "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" >
+ <node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
+ <interface name="com.example.MyService1.InterestingInterface">
+ <method name="AddContact">
+ <arg name="name" direction="in" type="s">
+ <doc:doc><doc:summary>Name of new contact</doc:summary></doc:doc>
+ </arg>
+ <arg name="email" direction="in" type="s">
+ <doc:doc><doc:summary>E-mail address of new contact</doc:summary></doc:doc>
+ </arg>
+ <arg name="id" direction="out" type="u">
+ <doc:doc><doc:summary>ID of newly added contact</doc:summary></doc:doc>
+ </arg>
+ <doc:doc>
+ <doc:description>
+ <doc:para>
+ Adds a new contact to the address book with their name and
+ e-mail address.
+ </doc:para>
+ </doc:description>
+ </doc:doc>
+ </method>
+ </interface>
+ </node>
+
+If an interface defined by service A needs to be used by client B, client B
+should declare a build time dependency on service A, and use the installed copy
+of the interface file for any code generation it has to do. It should $em(not)
+have a local copy of the interface, as that could then go out of sync with the
+canonical copy in service A’s git repository.
+
+== API versioning
+ [id="api-versioning"]
+
+$link[>>http://ometer.com/parallel.html](Just like C APIs), D-Bus interfaces
+should be designed to be usable in parallel with API-incompatible versions. This
+is achieved by including a version number in each interface name, service name
+and object path which is incremented on every backwards-incompatible change.
+
+Version numbers should be included in all APIs from the first release, as that
+means moving to a new version is as simple as incrementing the number, rather
+than inserting a number everywhere, which takes more effort.
+
+New API can be added to a D-Bus interface without incrementing the version
+number, as such additions are still backwards-compatible. However, clients
+should gracefully handle the $code(org.freedesktop.DBus.Error.UnknownMethod)
+error reply from all D-Bus method calls if they want to run against older
+versions of the service which don’t implement new methods. (This also prevents
+use of generated bindings; any method which a client wants to gracefully fall
+back from should be called using a generic D-Bus method invocation rather than
+a specific generated binding.)
+
+When API is broken, changed or removed, the service’s version number must be
+bumped; for example, from $code(com.example.MyService1)
+to $code(com.example.MyService2). If backwards compatibility is maintained in
+the service by implementing both the old and new interfaces, the service can
+own $em(both) well-known names and clients can use whichever they support.
+
+As discussed in $link[>#annotations], new or deprecated APIs should be marked in
+the interface XML using annotations.
+
+Note, however, that supporting multiple interface versions simultaneously
+requires that $em(object paths) are versioned as well, so objects $em(must not)
+be put on the bus at the root path (‘/’). This is for technical reasons: signals
+sent from a D-Bus service have the originating service name overwritten by its
+unique name (e.g. $code(com.example.MyService2) is overwritten by $code(:1:15)).
+If object paths are shared between objects implementing two versions of the
+service’s interface, client programs cannot tell which object a signal has come
+from. The solution is to include the version number in all object paths, for
+example $code(/com/example/MyService1/Manager) instead of $code(/) or
+$code(/com/example/MyService/Manager).
+
+In summary, version numbers should be included in all service names, interface
+names and object paths:
+[list]
+* $code(com.example.MyService1)
+* $code(com.example.MyService1.InterestingInterface)
+* $code(com.example.MyService1.OtherInterface)
+* $code(/com/example/MyService1/Manager)
+* $code(/com/example/MyService1/OtherObject)
+
+== API design
+ [id="api-design"]
+
+D-Bus API design is broadly the same as C API design, but there are a few
+additional points to bear in mind which arise both from D-Bus’ features
+(explicit errors, signals and properties), and from its implementation as an IPC
+system.
+
+D-Bus method calls are much more expensive than C function calls, typically
+taking on the order of milliseconds to complete a round trip. Therefore, the
+design should minimize the number of method calls needed to perform an
+operation.
+
+The type system is very expressive, especially compared to C’s, and APIs should
+take full advantage of it.
+
+Similarly, its support for signals and properties differentiates it from normal
+C APIs, and well written D-Bus APIs make full use of these features where
+appropriate. They can be coupled with standard interfaces defined in the D-Bus
+specification to allow for consistent access to properties and objects in a
+hierarchy.
+
+=== Minimizing Round Trips
+ [id="round-trips"]
+
+Each D-Bus method call is a round trip from a client program to a service and
+back again, which is expensive — taking on the order of a millisecond. One of
+the top priorities in D-Bus API design is to minimize the number of round trips
+needed by clients. This can be achieved by a combination of providing specific
+convenience APIs and designing APIs which operate on large data sets in a single
+call, rather than requiring as many calls as elements in the data set.
+
+Consider an address book API, $code(com.example.MyService1.AddressBook). It
+might have an $code(AddContact(ss$) → (u$)) method to add a contact (taking name
+and e-mail address parameters and returning a unique contact ID), and a
+$code(RemoveContact(u$)) method to remove one by ID. In the normal case of
+operating on single contacts in the address book, these calls are optimal.
+However, if the user wants to import a list of contacts, or delete multiple
+contacts simultaneously, one call has to be made per contact — this could take
+a long time for large contact lists.
+
+Instead of the $code(AddContact) and $code(RemoveContact) methods, the interface
+could have an $code(UpdateContacts(a(ss$)au$) → (au$)) method, which takes an array
+of structs containing the new contacts’ details, and an array of IDs of the
+contacts to delete, and returns an array of IDs for the new contacts. This
+reduces the number of round trips needed to one.
+
+Adding convenience APIs to replace a series of common method calls with a single
+method call specifically for that task is best done after the API has been
+profiled and bottlenecks identified, otherwise it could lead to premature
+optimization. One area where convenience methods can typically be added
+is during initialization of a client, where multiple method calls are needed to
+establish its state with the service.
+
+=== Taking Advantage of the Type System
+ [id="type-system"]
+
+D-Bus’ type system is similar to Python’s, but with a terser syntax which may be
+unfamiliar to C developers. The key to using the type system effectively is
+to expose as much structure in types as possible. In particular, sending
+structured strings over D-Bus should be avoided, as they need to be built and
+parsed; both are complex operations which are prone to bugs.
+
+For APIs being used in constrained situations, enumerated values should be
+transmitted as unsigned integers. For APIs which need to be extended by third
+parties or which are used in more loosely coupled systems, enumerated values
+should be strings in some defined format.
+
+Transmitting values as integers means string parsing and matching can be
+avoided, the messages are more compact, and typos can be more easily avoided by
+developers (if, for example, C enums are used in the implementation).
+
+Transmitting values as strings means additional values can be defined by third
+parties without fear of conflicting over integer values; for instance by using
+the same reverse-domain-name namespacing as D-Bus interfaces.
+
+In both cases, the interface documentation should describe the meaning of each
+value. It should state whether the type can be extended in future and, if so,
+how the service and client should handle unrecognized values — typically by
+considering them equal to an ‘unknown’ or ‘failure’ value. Conventionally, zero
+is used as the ‘unknown’ value.
+
+[example]
+ For example, instead of:
+ [code style="invalid" mime="application/xml"]
+ <!--
+ Status:
+
+ Status of the object.
+ Valid statuses: ‘unknown’, ‘ready’, ‘complete’.
+ -->
+ <property name="Status" type="s" access="read" />
+
+ Use:
+ [code style="valid" mime="application/xml"]
+ <!--
+ Status:
+
+ Status of the object.
+ Valid statuses: 0 = Unknown, 1 = Ready, 2 = Complete.
+ Unrecognized statuses should be considered equal to Unknown.
+ -->
+ <property name="Status" type="u" access="read" />
+
+Similarly, enumerated values should be used instead of booleans, as they allow
+extra values to be added in future, and there is no ambiguity about the sense of
+the boolean value.
+
+[example]
+ For example, instead of:
+ [code style="invalid" mime="application/xml"]
+ <!--
+ MoveAddressBook:
+ @direction: %TRUE to move it up in the list, %FALSE to move it down
+
+ Move this address book up or down in the user’s list of address books.
+ Higher address books have their contacts displayed first in search
+ results.
+ -->
+ <method name="MoveAddressBook">
+ <arg name="direction" type="b" direction="in" />
+ </method>
+
+ Be more explicit than a boolean:
+ [code style="valid" mime="application/xml"]
+ <!--
+ MoveAddressBook:
+ @direction: 0 = Move it up in the list, 1 = Move it down
+
+ Move this address book up or down in the user’s list of address books.
+ Higher address books have their contacts displayed first in search
+ results.
+
+ Unrecognized enum values for @direction will result in the address book
+ not moving.
+ -->
+ <method name="MoveAddressBook">
+ <arg name="direction" type="u" direction="in" />
+ </method>
+
+Enumerated values should also be used instead of $em(human readable) strings,
+which should not be sent over the bus if possible. The service and client could
+be running in different locales, and hence interpret any human readable strings
+differently, or present them to the user in the wrong language. Transmit an
+enumerated value and convert it to a human readable string in the client.
+
+In situations where a service has received a human readable string from
+somewhere else, it should pass it on unmodified to the client, ideally with its
+locale alongside. Passing human readable information to a client is better than
+passing nothing.
+
+[example]
+ For example, instead of:
+ [code style="invalid" mime="application/xml"]
+ <!--
+ ProgressNotification:
+ @progress_message: Human readable progress message string.
+
+ Emitted whenever significant progress is made with some example
+ operation. The @progress_message can be displayed in a UI dialogue to
+ please the user.
+ -->
+ <signal name="ProgressNotification">
+ <arg name="progress_message" type="s" />
+ </method>
+
+ The progress should be reported as an enumerated value:
+ [code style="valid" mime="application/xml"]
+ <!--
+ ProgressNotification:
+ @progress_state: 0 = Preparing, 1 = In progress, 2 = Finished
+
+ Emitted whenever significant progress is made with some example
+ operation. The @progress_state is typically converted to a human readable
+ string and presented to the user. Unrecognized @progress_state values
+ should be treated as state 1, in progress.
+ -->
+ <signal name="ProgressNotification">
+ <arg name="progress_state" type="u" />
+ </method>
+
+D-Bus has none of the problems of signed versus unsigned integers which C has
+(specifically, it does not do implicit sign conversion), so integer types should
+always be chosen to be an appropriate size and signedness for the data they
+could possibly contain. Typically, unsigned values are more frequently needed
+than signed values.
+
+Structures can be used almost anywhere in a D-Bus type, and arrays of structures
+are particularly useful. Structures should be used wherever data fields are
+related. Note, however, that structures are not extensible in future, so always
+consider $link[>#extensibility].
+
+[example]
+ For example, instead of several identically-indexed arrays containing
+ different properties of the same set of items:
+ [code style="invalid" mime="application/xml"]
+ <!--
+ AddContacts:
+ @names: Array of contact names to add.
+ @emails: Corresponding array of contact e-mail addresses.
+ @ids: Returned array of the IDs of the new contacts. This will be the
+ same length as @names.
+
+ Add zero or more contacts to the address book, using their names and
+ e-mail addresses. @names and @emails must be the same length.
+ -->
+ <method name="AddContacts">
+ <arg name="names" type="as" direction="in" />
+ <arg name="emails" type="as" direction="in" />
+ <arg name="ids" type="au" direction="out" />
+ </method>
+
+ The arrays can be combined into a single array of structures:
+ [code style="invalid" mime="application/xml"]
+ <!--
+ AddContacts:
+ @details: Array of (contact name, contact e-mail address) to add.
+ @ids: Returned array of the IDs of the new contacts. This will be the
+ same length as @details.
+
+ Add zero or more contacts to the address book, using their names and
+ e-mail addresses.
+ -->
+ <method name="AddContacts">
+ <arg name="details" type="a(ss)" direction="in" />
+ <arg name="ids" type="au" direction="out" />
+ </method>
+
+Note that D-Bus arrays are automatically transmitted with their length, so there
+is no need to null-terminate them or encode their length separately.
+
+[comment]
+ FIXME: Mention maybe types and the extended kdbus/GVariant type system once
+ that’s stable and round-trip-ability is no longer a concern.
+
+=== Extensibility
+ [id="extensibility"]
+
+Some D-Bus APIs have very well-defined use cases, and will never need extension.
+Others are used in more loosely coupled systems which may change over time, and
+hence should be designed to be extensible from the beginning without the need
+to break API in future. This is a trade off between having a more complex API,
+and being able to easily extend it in future.
+
+The key tool for extensibility in D-Bus is $code(a{sv}), the dictionary mapping
+strings to variants. If well-defined namespaced strings are used as the
+dictionary keys, arbitrary D-Bus peers can add whatever information they need
+into the dictionary. Any other peer which understands it can query and retrieve
+the information; other peers will ignore it.
+
+The canonical example of an extensible API using $code(a{sv}) is
+$link[>>http://telepathy.freedesktop.org/spec/](Telepathy). It uses $code(a{sv})
+values as the final element in structures to allow them to be extended in
+future.
+
+A secondary tool is the use of flag fields in method calls. The set of accepted
+flags is entirely under the control of the interface designer and, as with
+enumerated types, can be extended in future without breaking API. Adding more
+flags allows the functionality of the method call to be tweaked.
+
+=== Using Signals, Properties and Errors
+ [id="using-the-features"]
+
+D-Bus method calls are explicitly asynchronous due to the latency inherent in
+IPC. This means that peers should not block on receiving a reply from a method
+call; they should schedule other work (in a main loop) and handle the reply when
+it is received. Even though method replies may take a while, the caller is
+$em(guaranteed) to receive exactly one reply eventually. This reply could be the
+return value from the method, an error from the method, or an error from the
+D-Bus daemon indicating the service failed in some way (e.g. due to crashing).
+
+Because of this, service implementations should be careful to always reply
+exactly once to each method call. Replying at the end of a long-running
+operation is correct — the client will patiently wait until the operation has
+finished and the reply is received.
+
+Note that D-Bus client bindings may implement synthetic timeouts of several
+tens of seconds, unless explicitly disabled for a call. For very long-running
+operations, you should disable the client bindings’ timeout and make it clear
+in the client’s UI that the application has not frozen and is simply running a
+long operation.
+
+An anti-pattern to avoid in this situation is to start a long-running operation
+when a method call is received, then to never reply to the method call and
+instead notify the client of completion of the operation via a signal. This
+approach is incorrect as signal emissions do not have a one-to-one relationship
+with method calls — the signal could theoretically be emitted multiple times, or
+never, which the client would not be able to handle.
+
+Similarly, use a D-Bus error reply to signify failure of an operation triggered
+by a method call, rather than using a custom error code in the method’s
+reply. This means that a reply always indicates success, and an error always
+indicates failure — rather than a reply indicating either depending on its
+parameters, and having to return dummy values in the other parameters. Using
+D-Bus error replies also means such failures can be highlighted in debugging
+tools, simplifying debugging.
+
+Clients should handle all possible standard and documented D-Bus errors for each
+method call. IPC inherently has more potential failures than normal C function
+calls, and clients should be prepared to handle all of them gracefully.
+
+=== Using Standard Interfaces
+ [id="standard-interfaces"]
+
+Use standard D-Bus interfaces where possible.
+
+==== Properties
+ [id="interface-properties"]
+
+The D-Bus specification defines the
+$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties]($code(org.freedesktop.DBus.Properties))
+interface, which should be used by all objects to notify clients of changes
+to their property values, with the $code(PropertiesChanged) signal. This signal
+eliminates the need for individual $code($var(PropertyName)Changed) signals, and
+allows multiple properties to be notified in a single signal emission, reducing
+IPC round trips. Similarly, the $code(Get) and $code(Set) methods can be used to
+manipulate properties on an object, eliminating redundant
+$code(Get$var(PropertyName)) and $code(Set$var(PropertyName)) methods.
+
+[example]
+ For example, consider an object implementing an interface
+ $code(com.example.MyService1.SomeInterface) with methods:
+ [list]
+ * $code(GetName($) → (s$))
+ * $code(SetName(s$) → ($))
+ * $code(GetStatus($) → (u$))
+ * $code(RunOperation(ss$) → (u$))
+ and signals:
+ [list]
+ * $code(NameChanged(u$))
+ * $code(StatusChanged(u$))
+
+ The interface could be cut down to a single method:
+ [list]
+ * $code(RunOperation(ss$) → (u$))
+ The object could then implement the $code(org.freedesktop.DBus.Properties)
+ interface and define properties:
+ [list]
+ * $code(Name) of type $code(s), read–write
+ * $code(Status) of type $code(u), read-only
+
+ The $code(NameChanged) and $code(StatusChanged) signals would be replaced by
+ $code(org.freedesktop.DBus.Properties.PropertiesChanged).
+
+==== Object Manager
+ [id="interface-object-manager"]
+
+The specification also defines the
+$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager]($code(org.freedesktop.DBus.ObjectManager))
+interface, which should be used whenever a service needs to expose a variable
+number of objects of the same class in a flat or tree-like structure, and
+clients are expected to be interested in most or all of the objects. For
+example, this could be used by an address book service which exposes multiple
+address books, each as a separate object. The $code(GetManagedObjects) method
+allows the full object tree to be queried, returning all the objects’ properties
+too, eliminating the need for further IPC round trips to query the properties.
+
+If clients are not expected to be interested in most of the exposed objects,
+$code(ObjectManager) should $em(not) be used, as it will send all of the objects
+to each client anyway, wasting bus bandwidth. A file manager, therefore, should
+not expose the entire file system hierarchy using $code(ObjectManager).
+
+[example]
+ For example, consider an object implementing an interface
+ $code(com.example.MyService1.AddressBookManager) with methods:
+ [list]
+ * $code(GetAddressBooks($) → (ao$))
+ and signals:
+ [list]
+ * $code(AddressBookAdded(o$))
+ * $code(AddressBookRemoved(o$))
+
+ If the manager object is at path
+ $code(/com/example/MyService1/AddressBookManager), each address book is a
+ child object, e.g.
+ $code(/com/example/MyService1/AddressBookManager/SomeAddressBook).
+
+ The interface could be eliminated, and the
+ $code(org.freedesktop.DBus.ObjectManager) interface implemented on the manager
+ object instead.
+
+ Calls to $code(GetAddressBooks) would become calls to $code(GetManagedObjects)
+ and emissions of the $code(AddressBookAdded) and $code(AddressBookRemoved)
+ signals would become emissions of $code(InterfacesAdded) and
+ $code(InterfacesRemoved).
+
+=== Naming Conventions
+ [id="naming-conventions"]
+
+All D-Bus names, from service names through to method parameters, follow a set
+of conventions. Following these conventions makes APIs more natural to use and
+consistent with all other services on the system.
+
+Services use reverse-domain-name notation, based on the domain name of the
+project providing the service (all in lower case), plus a unique name for the
+service (in camel case).
+
+[example]
+ For example, version 2 of an address book application called $code(ContactDex)
+ provided by a software vendor whose website is $code(chocolateteapot.com)
+ would use service name $code(com.chocolateteapot.ContactDex2).
+
+Almost all names use camel case with no underscores, as in the examples below.
+Method and signal parameters are an exception, using
+$code(lowercase_with_underscores). Type information is never encoded in the
+parameter name (i.e. $em(not)
+$link[>>http://en.wikipedia.org/wiki/Hungarian_notation](Hungarian notation)).
+
+[example]
+ [terms]
+ - Service Name
+ * $code(com.example.MyService1)
+ - Interface Name
+ * $code(com.example.MyService1.SomeInterface)
+ - Object Path (Root Object)
+ * $code(/com/example/MyService1)
+ - Object Path (Child Object)
+ * $code(/com/example/MyService1/SomeChild)
+ - Object Path (Grandchild Object)
+ * $code(/com/example/MyService1/AnotherChild/Grandchild1)
+ - Method Name
+ * $code(com.example.MyService1.SomeInterface.MethodName)
+ - Signal Name
+ * $code(com.example.MyService1.SomeInterface.SignalName)
+ - Property Name
+ * $code(com.example.MyService1.SomeInterface.PropertyName)
+
+See also: $link[>#api-versioning].
+
+== Code generation
+ [id="code-generation"]
+
+Rather than manually implementing both the server and client sides of a D-Bus
+interface, it is often easier to write the interface XML description and use a
+tool such as
+$link[>>https://developer.gnome.org/gio/stable/gdbus-codegen.html]($cmd(gdbus-codegen))
+to generate type-safe C APIs, then build the implementation using those. This
+avoids the tedious and error-prone process of writing code to build and read
+D-Bus parameter variants for each method call.
+
+Use of code generators is beyond the scope of this guide; for more information,
+see the
+$link[>>https://developer.gnome.org/gio/stable/gdbus-codegen.html]($cmd(gdbus-codegen)
+manual).
+
+== Annotations
+ [id="annotations"]
+
+Annotations may be added to the interface XML to expose metadata on the API
+which can be used by documentation or code generation tools to modify their
+output. Some standard annotations are given in the
+$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format](D-Bus
+specification), but further annotations may be defined by specific tools.
+
+For example, $cmd(gdbus-codegen) defines several useful annotations, listed on
+its man page.
+
+The following annotations are the most useful:
+
+[terms]
+- $code(org.freedesktop.DBus.Deprecated)
+* Mark a symbol as deprecated. This should be used whenever the API is changed,
+ specifying the version introducing the deprecation, the reason for
+ deprecation, and a replacement symbol to use.
+- $code(org.gtk.GDBus.Since)
+* Mark a symbol as having been added to the API after the initial release. This
+ should include the version the symbol was first added in.
+- $code(org.gtk.GDBus.C.Name) and $code(org.freedesktop.DBus.GLib.CSymbol)
+* Both used interchangeably to hint at a C function name to use when generating
+ code for a symbol. Use of this annotation can make generated bindings a lot
+ more pleasant to use.
+- $code(org.freedesktop.DBus.Property.EmitsChangedSignal)
+* Indicate whether a property is expected to emit change signals. This can
+ affect code generation, but is also useful documentation, as client programs
+ then know when to expect property change notifications and when they have to
+ requery.
+
+== Documentation
+ [id="documentation"]
+
+Also just like C APIs, D-Bus APIs must be documented. There are several methods
+for documenting the interfaces, methods, properties and signals in a D-Bus
+interface XML file, each unfortunately with their own downsides. You should
+choose the method which best matches the tooling and workflow you are using.
+
+=== XML Comments
+
+XML comments containing documentation in the
+$link[>>https://developer.gnome.org/gtk-doc-manual/stable/documenting_syntax.html.en](gtk-doc
+format) is the recommended format for use with
+$link[>>https://developer.gnome.org/gio/stable/gdbus-codegen.html]($cmd(gdbus-codegen)).
+Using $cmd(gdbus-codegen), these comments can be extracted, converted to DocBook
+format and included in the project’s API manual. For example:
+
+[listing]
+ [title]
+ Documentation Comments in D-Bus Interface XML
+ [desc]
+ Example gtk-doc–style documentation comments in the introspection XML for
+ the $code(org.freedesktop.DBus.Properties) interface.
+ [code mime="application/xml"]
+ <!--
+ org.freedesktop.DBus.Properties:
+ @short_description: Standard property getter/setter interface
+
+ Interface for all objects which expose properties on the bus, allowing
+ those properties to be got, set, and signals emitted to notify of changes
+ to the property values.
+ -->
+ <interface name="org.freedesktop.DBus.Properties">
+ <!--
+ Get:
+ @interface_name: Name of the interface the property is defined on.
+ @property_name: Name of the property to get.
+ @value: Property value, wrapped in a variant.
+
+ Retrieves the value of the property at @property_name on
+ @interface_name on this object. If @interface_name is an empty string,
+ all interfaces will be searched for @property_name; if multiple
+ properties match, the result is undefined.
+
+ If @interface_name or @property_name do not exist, a
+ #org.freedesktop.DBus.Error.InvalidArgs error is returned.
+ -->
+ <method name="Get">
+ <arg type="s" name="interface_name" direction="in"/>
+ <arg type="s" name="property_name" direction="in"/>
+ <arg type="v" name="value" direction="out"/>
+ </method>
+
+ <!--
+ PropertiesChanged:
+ @interface_name: Name of the interface the properties changed on.
+ @changed_properties: Map of property name to updated value for the
+ changed properties.
+ @invalidated_properties: List of names of other properties which have
+ changed, but whose updated values are not notified.
+
+ Emitted when one or more properties change values on @interface_name.
+ A property may be listed in @changed_properties or
+ @invalidated_properties depending on whether the service wants to
+ broadcast the property’s new value. If a value is large or infrequently
+ used, the service might not want to broadcast it, and will wait for
+ clients to request it instead.
+ -->
+ <signal name="PropertiesChanged">
+ <arg type="s" name="interface_name"/>
+ <arg type="a{sv}" name="changed_properties"/>
+ <arg type="as" name="invalidated_properties"/>
+ </signal>
+ </interface>
+
+[comment]
+ FIXME: This is only present to fix
+ $link[>>https://github.com/projectmallard/mallard-ducktype/issues/2].
+
+=== XML Annotations
+
+Documentation can also be added as annotation elements in the XML. This format
+is also supported by $cmd(gdbus-codegen), but gtk-doc comments are preferred.
+For example:
+
+[listing]
+ [title]
+ Documentation Annotations in D-Bus Interface XML
+ [desc]
+ Example GDBus documentation annotations in the introspection XML for
+ the $code(org.freedesktop.DBus.Properties) interface.
+ [code mime="application/xml"]
+ <interface name="org.freedesktop.DBus.Properties">
+ <annotation name="org.gtk.GDBus.DocString" value="Interface for all
+ objects which expose properties on the bus, allowing those properties to
+ be got, set, and signals emitted to notify of changes to the property
+ values."/>
+ <annotation name="org.gtk.GDBus.DocString.Short"
+ value="Standard property getter/setter interface"/>
+
+ <method name="Get">
+ <annotation name="org.gtk.GDBus.DocString" value="Retrieves the value of
+ the property at @property_name on @interface_name on this object. If
+ @interface_name is an empty string, all interfaces will be searched
+ for @property_name; if multiple properties match, the result is
+ undefined.
+
+ If @interface_name or @property_name do not exist, a
+ #org.freedesktop.DBus.Error.InvalidArgs error is returned."/>
+
+ <arg type="s" name="interface_name" direction="in">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="Name of the interface the property is defined on."/>
+ </arg>
+
+ <arg type="s" name="property_name" direction="in">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="Name of the property to get."/>
+ </arg>
+
+ <arg type="v" name="value" direction="out">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="Property value, wrapped in a variant."/>
+ </arg>
+ </method>
+
+ <signal name="PropertiesChanged">
+ <annotation name="org.gtk.GDBus.DocString" value="Emitted when one or
+ more properties change values on @interface_name. A property may be
+ listed in @changed_properties or @invalidated_properties depending on
+ whether the service wants to broadcast the property’s new value. If a
+ value is large or infrequently used, the service might not want to
+ broadcast it, and will wait for clients to request it instead."/>
+
+ <arg type="s" name="interface_name">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="Name of the interface the properties changed on."/>
+ </arg>
+
+ <arg type="a{sv}" name="changed_properties">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="Map of property name to updated value for the changed
+ properties."/>
+ </arg>
+
+ <arg type="as" name="invalidated_properties">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="List of names of other properties which have changed, but
+ whose updated values are not notified."/>
+ </arg>
+ </signal>
+ </interface>
+
+[comment]
+ FIXME: This is only present to fix
+ $link[>>https://github.com/projectmallard/mallard-ducktype/issues/2].
+
+== Service files
+ [id="service-files"]
+
+Each D-Bus service must install a $file(.service) file describing its service
+name and the command to run to start the service. This allows for service
+activation (see the
+$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-starting-services](D-Bus
+specification)).
+
+Service files must be named after the service’s well-known name, for example
+file $file(com.example.MyService1.service) for well-known name
+$code(com.example.MyService1). Files must be installed in
+$file($var($$(datadir$))/dbus-1/services) for the session bus and
+$file($var($$(datadir$))/dbus-1/system-services) for the system bus. Note, however,
+that services on the system bus almost always need a
+$link[>#security-policies](security policy) as well.
+
+== Security Policies
+ [id="security-policies"]
+
+At a high level, the D-Bus security model is:
+[list]
+* There is a system bus, and zero or more session buses.
+* Any process may connect to the system bus. The system bus limits which can own
+ names or send method calls, and only processes running as privileged users can
+ receive unicast messages not addressed to them. Every process may receive
+ broadcasts.
+* Each session bus has an owner (a user). Only its owner may connect; on
+ general-purpose Linux, a session bus is not treated as a privilege boundary,
+ so there is no further privilege separation between processes on it.
+
+Full coverage of securing D-Bus services is beyond the scope of this guide,
+however there are some steps which you can take when designing an API to ease
+security policy implementation.
+
+D-Bus security policies are written as XML files in
+$file($var($$(sysconfdir$)/dbus-1/system.d)) and
+$file($var($$(sysconfdir$)/dbus-1/session.d)) and use an allow/deny model, where
+each message (method call, signal emission, etc.) can be allowed or denied
+according to the sum of all policy rules which match it. Each $code(<allow>) or
+$code(<deny>) rule in the policy should have the $code(own),
+$code(send_destination) or $code(receive_sender) attribute set.
+
+When designing an API, bear in mind the need to write and install such a
+security policy, and consider splitting up methods or providing more restricted
+versions which accept constrained parameters, so that they can be exposed with
+less restrictive security policies if needed by less trusted clients.
+
+Secondly, the default D-Bus security policy for the system bus is restrictive
+enough to allow sensitive data, such as passwords, to be safely sent over the
+bus in unicast messages (including unicast signals); so there is no need to
+complicate APIs by implementing extra security. Note, however, that sensitive
+data must $em(not) be sent in broadcast signals, as they can be seen by all
+peers on the bus. The default policy for the session bus is not restrictive, but
+it is typically not a security boundary.
+
+== Debugging
+ [id="debugging"]
+
+Debugging services running on D-Bus can be tricky, especially if they are
+launched via service activation and hence in an environment out of your control.
+
+Three main tools are available: D-Bus Monitor, Bustle and D-Feet.
+
+=== D-Bus Monitor
+ [id="dbus-monitor"]
+
+$link[>>http://dbus.freedesktop.org/doc/dbus-monitor.1.html]($cmd(dbus-monitor))
+is a core D-Bus tool, and allows eavesdropping on the session or system bus,
+printing all messages it sees. The messages may be filtered using a standard
+$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-routing-match-rules](D-Bus
+match rule) to make the stream more manageable.
+
+Previous versions of D-Bus have required the security policy for the system bus
+to be manually relaxed to allow eavesdropping on all messages. This meant that
+debugging it was difficult and insecure. The latest versions of D-Bus add
+support for monitor-only connections for the root user, which means that
+$cmd(dbus-monitor) can be run as root to painlessly monitor all messages on the
+system bus without modifying its security policy.
+
+=== Bustle
+ [id="bustle"]
+
+$link[>>http://willthompson.co.uk/bustle/](Bustle) is a graphical version of
+$cmd(dbus-monitor), with a UI focused on profiling D-Bus performance by plotting
+messages on a timeline. It is ideal for finding bottlenecks in IPC performance
+between a service and client.
+
+=== D-Feet
+ [id="d-feet"]
+
+$link[>>https://wiki.gnome.org/Apps/DFeet](D-Feet) is an introspection tool for
+D-Bus, which displays all peers on the bus graphically, with their objects,
+interfaces, methods, signals and properties listed for examination. It is useful
+for debugging all kinds of issues related to presence of services on the bus
+and the objects they expose.
diff --git a/doc/dbus-daemon.1.xml.in b/doc/dbus-daemon.1.xml.in
index cd7942c3..df67a907 100644
--- a/doc/dbus-daemon.1.xml.in
+++ b/doc/dbus-daemon.1.xml.in
@@ -50,9 +50,9 @@ per-user-login-session message bus (started each time a user logs in).
a different configuration file.</para>
<para>The --session option is equivalent to
-"--config-file=@EXPANDED_SYSCONFDIR@/dbus-1/session.conf" and the --system
+"--config-file=@EXPANDED_DATADIR@/dbus-1/session.conf" and the --system
option is equivalent to
-"--config-file=@EXPANDED_SYSCONFDIR@/dbus-1/system.conf". By creating
+"--config-file=@EXPANDED_DATADIR@/dbus-1/system.conf". By creating
additional configuration files and using the --config-file option,
additional special-purpose message bus daemons could be created.</para>
@@ -181,9 +181,10 @@ specification and its backward compatibility is not guaranteed; this
document is documentation, not specification.</para>
<para>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
-&lt;include&gt; a system-local.conf or session-local.conf; you can put local
+configured in the files "@EXPANDED_DATADIR@/dbus-1/system.conf" and
+"@EXPANDED_DATADIR@/dbus-1/session.conf". These files normally
+&lt;include&gt; a system-local.conf or session-local.conf in
+@EXPANDED_SYSCONFDIR@/dbus-1; you can put local
overrides in those files to avoid modifying the primary configuration
files.</para>
@@ -270,6 +271,7 @@ Only files ending in ".conf" are included.</para>
<para>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_DATADIR@/dbus-1/system.d or
@EXPANDED_SYSCONFDIR@/dbus-1/system.d that allowed all apps to receive
this message and allowed the printer daemon user to send it.</para>
@@ -396,12 +398,14 @@ DBUS_SESSION_BUS_ADDRESS is set.</para>
used in a listenable address to configure the interface on which
the server will listen: either the hostname is the IP address of
one of the local machine's interfaces (most commonly 127.0.0.1),
-or a DNS name that resolves to one of those IP addresses, or '*'
-to listen on all interfaces simultaneously. If not specified,
+a DNS name that resolves to one of those IP addresses, '0.0.0.0'
+to listen on all IPv4 interfaces simultaneously, or '::'
+to listen on all IPv4 and IPv6 interfaces simultaneously (if supported
+by the OS). If not specified,
the default is the same value as "host".</para>
-<para>Example: &lt;listen&gt;tcp:host=localhost,bind=*,port=0&lt;/listen&gt;</para>
+<para>Example: &lt;listen&gt;tcp:host=localhost,bind=0.0.0.0,port=0&lt;/listen&gt;</para>
<itemizedlist remap='TP'>
@@ -476,7 +480,7 @@ This option defaults to @EXPANDED_DATADIR@/dbus-1/system-services.</para>
<para>The &lt;standard_system_servicedirs/&gt; option is only relevant to the
per-system bus daemon defined in
-@EXPANDED_SYSCONFDIR@/dbus-1/system.conf. Putting it in any other
+@EXPANDED_DATADIR@/dbus-1/system.conf. Putting it in any other
configuration file would probably be nonsense.</para>
<itemizedlist remap='TP'>
@@ -492,7 +496,7 @@ the dbus-daemon-launch-helper executable in located in libexec.</para>
<para>The &lt;servicehelper/&gt; option is only relevant to the per-system bus daemon
-defined in @EXPANDED_SYSCONFDIR@/dbus-1/system.conf. Putting it in any other
+defined in @EXPANDED_DATADIR@/dbus-1/system.conf. Putting it in any other
configuration file would probably be nonsense.</para>
<itemizedlist remap='TP'>
@@ -807,6 +811,31 @@ Right now the default will be the security context of the bus itself.</para>
<para>If two &lt;associate&gt; elements specify the same name, the element
appearing later in the configuration file will be used.</para>
+<itemizedlist remap='TP'>
+
+ <listitem><para><emphasis remap='I'>&lt;apparmor&gt;</emphasis></para></listitem>
+
+
+</itemizedlist>
+
+<para>The &lt;apparmor&gt; element is used to configure AppArmor mediation on
+the bus. It can contain one attribute that specifies the mediation mode:</para>
+
+<literallayout remap='.nf'>
+ &lt;apparmor mode="(enabled|disabled|required)"/&gt;
+</literallayout> <!-- .fi -->
+
+<para>The default mode is "enabled". In "enabled" mode, AppArmor mediation
+will be performed if AppArmor support is available in the kernel. If it is not
+available, dbus-daemon will start but AppArmor mediation will not occur. In
+"disabled" mode, AppArmor mediation is disabled. In "required" mode, AppArmor
+mediation will be enabled if AppArmor support is available, otherwise
+dbus-daemon will refuse to start.</para>
+
+<para>The AppArmor mediation mode of the bus cannot be changed after the bus
+starts. Modifying the mode in the configuration file and sending a SIGHUP
+signal to the daemon has no effect on the mediation mode.</para>
+
</refsect1>
<refsect1 id='selinux'><title>SELinux</title>
@@ -874,6 +903,37 @@ itself will be used.</para>
</refsect1>
+<refsect1 id='apparmor'><title>AppArmor</title>
+<para>The AppArmor confinement context is stored when applications connect to
+the bus. The confinement context consists of a label and a confinement mode.
+When a security decision is required, the daemon uses the confinement context
+to query the AppArmor policy to determine if the action should be allowed or
+denied and if the action should be audited.</para>
+
+<para>The daemon performs AppArmor security checks in three places.</para>
+
+<para>First, any time a message is routed from one connection to another
+connection, the bus daemon will check permissions with the label of the first
+connection as source, label and/or connection name of the second connection as
+target, along with the bus name, the path name, the interface name, and the
+member name. Reply messages, such as method_return and error messages, are
+implicitly allowed if they are in response to a message that has already been
+allowed.</para>
+
+<para>Second, any time a connection asks to own a name, the bus daemon will
+check permissions with the label of the connection as source, the requested
+name as target, along with the bus name.</para>
+
+<para>Third, any time a connection attempts to eavesdrop, the bus daemon will
+check permissions with the label of the connection as the source, along with
+the bus name.</para>
+
+<para>AppArmor rules for bus mediation are not stored in the bus configuration
+files. They are stored in the application's AppArmor profile. Please see
+<emphasis remap='I'>apparmor.d(5)</emphasis> for more details.</para>
+
+</refsect1>
+
<refsect1 id='debugging'><title>DEBUGGING</title>
<para>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.</para>
diff --git a/doc/dbus-launch.1.xml.in b/doc/dbus-launch.1.xml.in
index 31dd6eac..5135d9ca 100644
--- a/doc/dbus-launch.1.xml.in
+++ b/doc/dbus-launch.1.xml.in
@@ -106,7 +106,7 @@ run by your X session, such as
or
<filename>~/.Xclients</filename>.</para>
-<para>To start a D-Bus session within a text\(hymode session,
+<para>To start a D-Bus session within a text-mode session,
do not use <emphasis remap='B'>dbus-launch</emphasis>.
Instead, see <citerefentry><refentrytitle>dbus-run-session</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
</para>
diff --git a/doc/dbus-monitor.1.xml.in b/doc/dbus-monitor.1.xml.in
index af05e3aa..2f807d2f 100644
--- a/doc/dbus-monitor.1.xml.in
+++ b/doc/dbus-monitor.1.xml.in
@@ -22,7 +22,7 @@
<cmdsynopsis>
<command>dbus-monitor</command>
<group choice='opt'><arg choice='plain'>--system </arg><arg choice='plain'>--session </arg><arg choice='plain'>--address <replaceable>ADDRESS</replaceable></arg></group>
- <group choice='opt'><arg choice='plain'>--profile </arg><arg choice='plain'>--monitor </arg></group>
+ <group choice='opt'><arg choice='plain'>--profile </arg><arg choice='plain'>--monitor </arg><arg choice='plain'>--pcap </arg><arg choice='plain'>--binary </arg></group>
<arg choice='opt'><arg choice='plain'><replaceable>watch</replaceable></arg><arg choice='plain'><replaceable>expressions</replaceable></arg></arg>
<sbr/>
</cmdsynopsis>
@@ -44,11 +44,22 @@ monitor the system or session buses respectively. If neither is
specified, <command>dbus-monitor</command> monitors the session bus.</para>
-<para><command>dbus-monitor</command> has two different output modes, the 'classic'-style
-monitoring mode and profiling mode. The profiling format is a compact
+<para><command>dbus-monitor</command> has two different text 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,
+and monitoring output format respectively.</para>
+
+<para><command>dbus-monitor</command> also has two binary output modes.
+ The binary mode, selected by <literal>--binary</literal>, outputs the
+ entire binary message stream (without the initial authentication handshake).
+ The PCAP mode, selected by <literal>--pcap</literal>, adds a
+ PCAP file header to the beginning of the output, and prepends a PCAP
+ message header to each message; this produces a binary file that can
+ be read by, for instance, Wireshark.</para>
+
+<para>If no mode is specified,
<command>dbus-monitor</command> uses the monitoring output format.</para>
diff --git a/doc/dbus-run-session.1.xml.in b/doc/dbus-run-session.1.xml.in
index 5181a8b1..a7ec28a4 100644
--- a/doc/dbus-run-session.1.xml.in
+++ b/doc/dbus-run-session.1.xml.in
@@ -63,8 +63,9 @@ or relying on there already being a D-Bus session active, for instance:</para>
<citerefentry><refentrytitle>automake</refentrytitle><manvolnum>1</manvolnum></citerefentry>):</para>
<literallayout remap='.nf'>
- TESTS_ENVIRONMENT = MY_DEBUG=all dbus-run-session --
-
+ AM_TESTS_ENVIRONMENT = export MY_DEBUG=all;
+ LOG_COMPILER = dbus-run-session
+ AM_LOG_FLAGS = --
</literallayout></refsect1>
<refsect1 id='options'><title>OPTIONS</title>
diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml
index f6b02152..1e0fe207 100644
--- a/doc/dbus-specification.xml
+++ b/doc/dbus-specification.xml
@@ -6,8 +6,8 @@
<article id="index">
<articleinfo>
<title>D-Bus Specification</title>
- <releaseinfo>Version 0.23</releaseinfo>
- <date>2014-01-06</date>
+ <releaseinfo>Version 0.26</releaseinfo>
+ <date>2015-02-19</date>
<authorgroup>
<author>
<firstname>Havoc</firstname>
@@ -71,6 +71,32 @@
</authorgroup>
<revhistory>
<revision>
+ <revnumber>0.26</revnumber>
+ <date>2015-02-19</date>
+ <authorinitials>smcv, rh</authorinitials>
+ <revremark>
+ GetConnectionCredentials can return LinuxSecurityLabel or
+ WindowsSID; add privileged BecomeMonitor method
+ </revremark>
+ </revision>
+ <revision>
+ <revnumber>0.25</revnumber>
+ <date>2014-11-10</date>
+ <authorinitials>smcv, lennart</authorinitials>
+ <revremark>
+ ALLOW_INTERACTIVE_AUTHORIZATION flag, EmitsChangedSignal=const
+ </revremark>
+ </revision>
+ <revision>
+ <revnumber>0.24</revnumber>
+ <date>2014-10-01</date>
+ <authorinitials>SMcV</authorinitials>
+ <revremark>
+ non-method-calls never expect a reply even without NO_REPLY_EXPECTED;
+ document how to quote match rules
+ </revremark>
+ </revision>
+ <revision>
<revnumber>0.23</revnumber>
<date>2014-01-06</date>
<authorinitials>SMcV, CY</authorinitials>
@@ -755,6 +781,7 @@
<tgroup cols="3">
<thead>
<row>
+ <entry>Category</entry>
<entry>Conventional Name</entry>
<entry>Code</entry>
<entry>Description</entry>
@@ -762,62 +789,77 @@
</thead>
<tbody>
<row>
+ <entry>reserved</entry>
<entry><literal>INVALID</literal></entry>
<entry>0 (ASCII NUL)</entry>
<entry>Not a valid type code, used to terminate signatures</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>BYTE</literal></entry>
<entry>121 (ASCII 'y')</entry>
<entry>8-bit unsigned integer</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>BOOLEAN</literal></entry>
<entry>98 (ASCII 'b')</entry>
<entry>Boolean value, 0 is <literal>FALSE</literal> and 1 is <literal>TRUE</literal>. Everything else is invalid.</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>INT16</literal></entry>
<entry>110 (ASCII 'n')</entry>
<entry>16-bit signed integer</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>UINT16</literal></entry>
<entry>113 (ASCII 'q')</entry>
<entry>16-bit unsigned integer</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>INT32</literal></entry>
<entry>105 (ASCII 'i')</entry>
<entry>32-bit signed integer</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>UINT32</literal></entry>
<entry>117 (ASCII 'u')</entry>
<entry>32-bit unsigned integer</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>INT64</literal></entry>
<entry>120 (ASCII 'x')</entry>
<entry>64-bit signed integer</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>UINT64</literal></entry>
<entry>116 (ASCII 't')</entry>
<entry>64-bit unsigned integer</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>DOUBLE</literal></entry>
<entry>100 (ASCII 'd')</entry>
<entry>IEEE 754 double</entry>
</row><row>
+ <entry>string-like, basic</entry>
<entry><literal>STRING</literal></entry>
<entry>115 (ASCII 's')</entry>
<entry>UTF-8 string (<emphasis>must</emphasis> be valid UTF-8). Must be nul terminated and contain no other nul bytes.</entry>
</row><row>
+ <entry>string-like, basic</entry>
<entry><literal>OBJECT_PATH</literal></entry>
<entry>111 (ASCII 'o')</entry>
<entry>Name of an object instance</entry>
</row><row>
+ <entry>string-like, basic</entry>
<entry><literal>SIGNATURE</literal></entry>
<entry>103 (ASCII 'g')</entry>
<entry>A type signature</entry>
</row><row>
+ <entry>container</entry>
<entry><literal>ARRAY</literal></entry>
<entry>97 (ASCII 'a')</entry>
<entry>Array</entry>
</row><row>
+ <entry>container</entry>
<entry><literal>STRUCT</literal></entry>
<entry>114 (ASCII 'r'), 40 (ASCII '('), 41 (ASCII ')')</entry>
<entry>Struct; type code 114 'r' is reserved for use in
@@ -825,10 +867,12 @@
concept of a struct, and must not appear in signatures
used on D-Bus.</entry>
</row><row>
+ <entry>container</entry>
<entry><literal>VARIANT</literal></entry>
<entry>118 (ASCII 'v') </entry>
<entry>Variant type (the type of the value is part of the value itself)</entry>
</row><row>
+ <entry>container</entry>
<entry><literal>DICT_ENTRY</literal></entry>
<entry>101 (ASCII 'e'), 123 (ASCII '{'), 125 (ASCII '}') </entry>
<entry>Entry in a dict or map (array of key-value pairs).
@@ -837,11 +881,13 @@
dict or dict-entry, and must not appear in signatures
used on D-Bus.</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>UNIX_FD</literal></entry>
<entry>104 (ASCII 'h')</entry>
<entry>Unix file descriptor</entry>
</row>
<row>
+ <entry>reserved</entry>
<entry>(reserved)</entry>
<entry>109 (ASCII 'm')</entry>
<entry>Reserved for <ulink
@@ -851,6 +897,7 @@
specified here</entry>
</row>
<row>
+ <entry>reserved</entry>
<entry>(reserved)</entry>
<entry>42 (ASCII '*')</entry>
<entry>Reserved for use in bindings/implementations to
@@ -858,6 +905,7 @@
and must not appear in signatures used on D-Bus.</entry>
</row>
<row>
+ <entry>reserved</entry>
<entry>(reserved)</entry>
<entry>63 (ASCII '?')</entry>
<entry>Reserved for use in bindings/implementations to
@@ -865,6 +913,7 @@
not appear in signatures used on D-Bus.</entry>
</row>
<row>
+ <entry>reserved</entry>
<entry>(reserved)</entry>
<entry>64 (ASCII '@'), 38 (ASCII '&amp;'),
94 (ASCII '^')</entry>
@@ -986,8 +1035,8 @@
<para>
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.
+ 67108864 (64 MiB). Implementations must not send or accept arrays
+ exceeding this length.
</para>
<para>
@@ -1192,8 +1241,8 @@
<para>
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.
+ and body is 2 to the 27th power or 134217728 (128 MiB).
+ Implementations must not send or accept messages exceeding this size.
</para>
<para>
@@ -1292,7 +1341,8 @@
<row>
<entry><literal>METHOD_CALL</literal></entry>
<entry>1</entry>
- <entry>Method call.</entry>
+ <entry>Method call. This message type may prompt a
+ reply.</entry>
</row>
<row>
<entry><literal>METHOD_RETURN</literal></entry>
@@ -1329,11 +1379,26 @@
<row>
<entry><literal>NO_REPLY_EXPECTED</literal></entry>
<entry>0x1</entry>
- <entry>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.
+ <entry>
+ <para>
+ This message does not expect method return replies or
+ error replies, even if it is of a type that can
+ have a reply; the reply can be omitted as an
+ optimization. It is compliant with this specification
+ to return the reply despite this flag, although doing
+ so on a bus with a non-trivial security policy
+ (such as the well-known system bus) may result in
+ access denial messages being logged for the reply.
+ </para>
+ <para>
+ Note that METHOD_CALL is the only message type currently
+ defined in this specification that can expect a reply,
+ so the presence or absence of this flag in the other
+ three message types that are currently
+ documented is meaningless: replies to those message
+ types should not be sent, whether this flag is present
+ or not.
+ </para>
</entry>
</row>
<row>
@@ -1343,6 +1408,66 @@
for the destination name in response to this message.
</entry>
</row>
+ <row>
+ <entry><literal>ALLOW_INTERACTIVE_AUTHORIZATION</literal></entry>
+ <entry>0x4</entry>
+ <entry>
+ <para>
+ This flag may be set on a method call message to
+ inform the receiving side that the caller is prepared
+ to wait for interactive authorization, which might
+ take a considerable time to complete. For instance,
+ if this flag is set, it would be appropriate to
+ query the user for passwords or confirmation via
+ Polkit or a similar framework.
+ </para>
+ <para>
+ This flag is only useful when
+ unprivileged code calls a more privileged method call,
+ and an authorization framework is deployed that allows
+ possibly interactive authorization. If no such framework
+ is deployed it has no effect. This flag should not
+ be set by default by client implementations. If it is
+ set, the caller should also set a suitably long timeout
+ on the method call to make sure the user interaction
+ may complete. This flag is only valid for method call
+ messages, and shall be ignored otherwise.
+ </para>
+ <para>
+ Interaction that takes place as a part of the
+ effect of the method being called is outside the scope
+ of this flag, even if it could also be characterized
+ as authentication or authorization. For instance, in
+ a method call that directs a network management service
+ to attempt to connect to a virtual private network,
+ this flag should control how the network management
+ service makes the decision "is this user allowed to
+ change system network configuration?", but it should
+ not affect how or whether the network management
+ service interacts with the user to obtain the credentials
+ that are required for access to the VPN.
+ </para>
+ <para>
+ If a this flag is not set on a method call, and a
+ service determines that the requested operation is
+ not allowed without interactive authorization, but
+ could be allowed after successful interactive
+ authorization, it may return the
+ <literal>org.freedesktop.DBus.Error.InteractiveAuthorizationRequired</literal>
+ error.
+ </para>
+ <para>
+ The absence of this flag does not guarantee that
+ interactive authorization will not be applied, since
+ existing services that pre-date this flag might
+ already use interactive authorization. However,
+ existing D-Bus APIs that will use interactive
+ authorization should document that the call may take
+ longer than usual, and new D-Bus APIs should avoid
+ interactive authorization in the absence of this flag.
+ </para>
+ </entry>
+ </row>
</tbody>
</tgroup>
</informaltable>
@@ -2977,9 +3102,12 @@
For instance, listening on <literal>tcp:host=127.0.0.1</literal>
might result in the connectable address
<literal>tcp:host=127.0.0.1,port=30958</literal>,
- or listening on <literal>unix:tmpdir=/tmp</literal>
+ listening on <literal>unix:tmpdir=/tmp</literal>
+ might result in the connectable address
+ <literal>unix:abstract=/tmp/dbus-U8OSdmf7</literal>, or
+ listening on <literal>unix:runtime=yes</literal>
might result in the connectable address
- <literal>unix:abstract=/tmp/dbus-U8OSdmf7</literal>.
+ <literal>unix:path=/run/user/1234/bus</literal>.
</para>
</sect1>
@@ -3019,6 +3147,9 @@
Unix addresses that specify <literal>tmpdir</literal> are only
listenable: the corresponding connectable address will specify
either <literal>path</literal> or <literal>abstract</literal>.
+ Similarly, Unix addresses that specify <literal>runtime</literal>
+ are only listenable, and the corresponding connectable address
+ will specify <literal>path</literal>.
</para>
<sect3 id="transports-unix-domain-sockets-addresses">
<title>Server Address Format</title>
@@ -3051,12 +3182,17 @@
<entry>(string)</entry>
<entry>unique string (path) in the abstract namespace. If set, the "path" or "tmpdir" key must not be set. This key is only supported on platforms with "abstract Unix sockets", of which Linux is the only known example.</entry>
</row>
+ <row>
+ <entry>runtime</entry>
+ <entry><literal>yes</literal></entry>
+ <entry>If given, This key can only be used in server addresses, not in client addresses. If set, its value must be <literal>yes</literal>. This is typically used in an address string like <literal>unix:runtime=yes;unix:tmpdir=/tmp</literal> so that there can be a fallback if <literal>XDG_RUNTIME_DIR</literal> is not set.</entry>
+ </row>
</tbody>
</tgroup>
</informaltable>
<para>
Exactly one of the keys <literal>path</literal>,
- <literal>abstract</literal> or
+ <literal>abstract</literal>, <literal>runtime</literal> or
<literal>tmpdir</literal> must be provided.
</para>
</sect3>
@@ -3894,7 +4030,7 @@
</row>
<row>
<entry>org.freedesktop.DBus.Property.EmitsChangedSignal</entry>
- <entry>true,invalidates,false</entry>
+ <entry>true,invalidates,const,false</entry>
<entry>
<para>
If set to <literal>false</literal>, the
@@ -3904,6 +4040,12 @@
guaranteed to be emitted if the property changes.
</para>
<para>
+ If set to <literal>const</literal> the property never
+ changes value during the lifetime of the object it
+ belongs to, and hence the signal is never emitted for
+ it.
+ </para>
+ <para>
If set to <literal>invalidates</literal> the signal
is emitted but the value is not included in the
signal.
@@ -3919,6 +4061,17 @@
defaults to the value specified in the enclosing
interface element.
</para>
+ <para>
+ This annotation is intended to be used by code
+ generators to implement client-side caching of
+ property values. For all properties for which the
+ annotation is set to <literal>const</literal>,
+ <literal>invalidates</literal> or
+ <literal>true</literal> the client may
+ unconditionally cache the values as the properties
+ don't change or notifications are generated for them
+ if they do.
+ </para>
</entry>
</row>
</tbody>
@@ -4423,7 +4576,9 @@
<literal>DESTINATION</literal> field is absent, it is considered to
be a <firstterm>broadcast signal</firstterm>, and is sent to all
applications with <firstterm>message matching rules</firstterm> that
- match the message. Most signal messages are broadcasts.
+ match the message. Most signal messages are broadcasts, and
+ no other message types currently defined in this specification
+ may be broadcast.
</para>
<para>
@@ -4463,7 +4618,7 @@
<para>
Message bus implementations may impose a security policy which
prevents certain messages from being sent or received.
- When a message cannot be sent or received due to a security
+ When a method call message cannot be sent or received due to a security
policy, the message bus should send an error reply, unless the
original message had the <literal>NO_REPLY</literal> flag.
</para>
@@ -4499,6 +4654,13 @@
adding the same rule with the <literal>eavesdrop</literal> match
omitted.
</para>
+
+ <para>
+ Eavesdropping interacts poorly with buses with non-trivial
+ access control restrictions. The
+ <xref linkend="bus-messages-become-monitor"/> method provides
+ an alternative way to monitor buses.
+ </para>
</sect3>
<sect3 id="message-bus-routing-match-rules">
@@ -4533,6 +4695,32 @@
"type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',path='/bar/foo',destination=':452345.34',arg2='bar'"
</para>
<para>
+ Within single quotes (ASCII apostrophe, U+0027), a backslash
+ (U+005C) represents itself, and an apostrophe ends the quoted
+ section. Outside single quotes, \' (backslash, apostrophe)
+ represents an apostrophe, and any backslash not followed by
+ an apostrophe represents itself. For instance, the match rules
+ <literal>arg0=''\''',arg1='\',arg2=',',arg3='\\'</literal> and
+ <literal>arg0=\',arg1=\,arg2=',',arg3=\\</literal>
+ both match messages where the arguments are a 1-character string
+ containing an apostrophe, a 1-character string containing a
+ backslash, a 1-character string containing a comma, and a
+ 2-character string containing two backslashes<footnote>
+ <para>
+ This idiosyncratic quoting style is based on the rules for
+ escaping items to appear inside single-quoted strings
+ in POSIX <literal>/bin/sh</literal>, but please
+ note that backslashes that are not inside single quotes have
+ different behaviour. This syntax does not offer any way to
+ represent an apostrophe inside single quotes (it is necessary
+ to leave the single-quoted section, backslash-escape the
+ apostrophe and re-enter single quotes), or to represent a
+ comma outside single quotes (it is necessary to wrap it in
+ a single-quoted section).
+ </para>
+ </footnote>.
+ </para>
+ <para>
The following table describes the keys that can be used to create
a match rule.
<informaltable>
@@ -5829,6 +6017,65 @@
this concept. On Unix, this is the process ID defined by
POSIX.</entry>
</row>
+ <row>
+ <entry>WindowsSID</entry>
+ <entry>STRING</entry>
+ <entry>The Windows security identifier in its string form,
+ e.g. "S-1-5-21-3623811015-3361044348-30300820-1013" for
+ a domain or local computer user or "S-1-5-18" for the
+ LOCAL_SYSTEM user</entry>
+ </row>
+
+ <row>
+ <entry>LinuxSecurityLabel</entry>
+ <entry>ARRAY of BYTE</entry>
+ <entry>
+ <para>On Linux systems, the security label that would result
+ from the SO_PEERSEC getsockopt call. The array contains
+ the non-zero bytes of the security label in an unspecified
+ ASCII-compatible encoding<footnote>
+ <para>It could be ASCII or UTF-8, but could also be
+ ISO Latin-1 or any other encoding.</para>
+ </footnote>, followed by a single zero byte.</para>
+ <para>
+ For example, the SELinux context
+ <literal>system_u:system_r:init_t:s0</literal>
+ (a string of length 27) would be encoded as 28 bytes
+ ending with ':', 's', '0', '\x00'.<footnote>
+ <para>Note that this is not the same as the older
+ GetConnectionSELinuxContext method, which does
+ not append the zero byte. Always appending the
+ zero byte allows callers to read the string
+ from the message payload without copying.</para>
+ </footnote>
+ </para>
+ <para>
+ On SELinux systems this is the SELinux context, as output
+ by <literal>ps -Z</literal> or <literal>ls -Z</literal>.
+ Typical values might include
+ <literal>system_u:system_r:init_t:s0</literal>,
+ <literal>unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023</literal>,
+ or
+ <literal>unconfined_u:unconfined_r:chrome_sandbox_t:s0-s0:c0.c1023</literal>.
+ </para>
+ <para>
+ On Smack systems, this is the Smack label.
+ Typical values might include
+ <literal>_</literal>, <literal>*</literal>,
+ <literal>User</literal>, <literal>System</literal>
+ or <literal>System::Shared</literal>.
+ </para>
+ <para>
+ On AppArmor systems, this is the AppArmor context,
+ a composite string encoding the AppArmor label (one or more
+ profiles) and the enforcement mode.
+ Typical values might include <literal>unconfined</literal>,
+ <literal>/usr/bin/firefox (enforce)</literal> or
+ <literal>user1 (complain)</literal>.
+ </para>
+ </entry>
+ </row>
+
</tbody>
</tgroup>
</informaltable>
@@ -6060,6 +6307,96 @@
</para>
</sect3>
+ <sect3 id="bus-messages-become-monitor">
+ <title><literal>org.freedesktop.DBus.Monitoring.BecomeMonitor</literal></title>
+ <para>
+ As a method:
+ <programlisting>
+ BecomeMonitor (in ARRAY of STRING rule, in UINT32 flags)
+ </programlisting>
+ Message arguments:
+ <informaltable>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Argument</entry>
+ <entry>Type</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>0</entry>
+ <entry>ARRAY of STRING</entry>
+ <entry>Match rules to add to the connection</entry>
+ </row>
+ <row>
+ <entry>1</entry>
+ <entry>UINT32</entry>
+ <entry>Not used, must be 0</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+
+ <para>
+ Converts the connection into a <emphasis>monitor
+ connection</emphasis> which can be used as a debugging/monitoring
+ tool. Only a user who is privileged on this
+ bus (by some implementation-specific definition) may create
+ monitor connections<footnote>
+ <para>
+ In the reference implementation,
+ the default configuration is that each user (identified by
+ numeric user ID) may monitor their own session bus,
+ and the root user (user ID zero) may monitor the
+ system bus.
+ </para>
+ </footnote>.
+ </para>
+
+ <para>
+ Monitor connections lose all their bus names, including the unique
+ connection name, and all their match rules. Sending messages on a
+ monitor connection is not allowed: applications should use a private
+ connection for monitoring.
+ </para>
+
+ <para>
+ Monitor connections may receive all messages, even messages that
+ should only have gone to some other connection ("eavesdropping").
+ The first argument is a list of match rules, which replace any
+ match rules that were previously active for this connection.
+ These match rules are always treated as if they contained the
+ special <literal>eavesdrop='true'</literal> member.
+ </para>
+
+ <para>
+ As a special case, an empty list of match rules (which would
+ otherwise match nothing, making the monitor useless) is treated
+ as a shorthand for matching all messages.
+ </para>
+
+ <para>
+ The second argument might be used for flags to influence the
+ behaviour of the monitor connection in future D-Bus versions.
+ </para>
+
+ <para>
+ Message bus implementations should attempt to minimize the
+ side-effects of monitoring — in particular, unlike ordinary
+ eavesdropping, monitoring the system bus does not require the
+ access control rules to be relaxed, which would change the set
+ of messages that can be delivered to their (non-monitor)
+ destinations. However, it is unavoidable that monitoring
+ will increase the message bus's resource consumption. In
+ edge cases where there was barely enough time or memory without
+ monitoring, this might result in message deliveries failing
+ when they would otherwise have succeeded.
+ </para>
+ </sect3>
+
</sect2>
</sect1>
diff --git a/doc/dbus-test-tool.1.xml.in b/doc/dbus-test-tool.1.xml.in
new file mode 100644
index 00000000..091dee14
--- /dev/null
+++ b/doc/dbus-test-tool.1.xml.in
@@ -0,0 +1,325 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
+<refentry id="dbus-test-tool.1">
+ <refentryinfo>
+ <copyright>
+ <year>2015</year>
+ <holder>Collabora Ltd.</holder>
+ </copyright>
+ <legalnotice>
+ <para>This man page is distributed under the same terms as
+ dbus-test-tool (GPL-2+). There is NO WARRANTY, to the extent
+ permitted by law.</para>
+ </legalnotice>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>dbus-test-tool</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="manual">User Commands</refmiscinfo>
+ <refmiscinfo class="source">D-Bus</refmiscinfo>
+ <refmiscinfo class="version">@DBUS_VERSION@</refmiscinfo>
+ </refmeta>
+ <refnamediv>
+ <refname>dbus-test-tool</refname>
+ <refpurpose>D-Bus traffic generator and test tool</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv id="synopsis">
+ <cmdsynopsis>
+ <command>dbus-test-tool</command>
+ <arg choice="plain">black-hole</arg>
+ <group choice="opt">
+ <arg choice="plain">--session</arg>
+ <arg choice="plain">--system</arg>
+ </group>
+ <arg choice="opt">--name=<replaceable>NAME</replaceable></arg>
+ <arg choice="opt">--no-read</arg>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>dbus-test-tool</command>
+ <arg choice="plain">echo</arg>
+ <group choice="opt">
+ <arg choice="plain">--session</arg>
+ <arg choice="plain">--system</arg>
+ </group>
+ <arg choice="opt">--name=<replaceable>NAME</replaceable></arg>
+ <arg choice="opt">--sleep=<replaceable>MS</replaceable></arg>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>dbus-test-tool</command>
+ <arg choice="plain">spam</arg>
+ <group choice="opt">
+ <arg choice="plain">--session</arg>
+ <arg choice="plain">--system</arg>
+ </group>
+ <arg choice="opt">--dest=<replaceable>NAME</replaceable></arg>
+ <arg choice="opt">--count=<replaceable>N</replaceable></arg>
+ <arg choice="opt">--flood</arg>
+ <arg choice="opt">--ignore-errors</arg>
+ <arg choice="opt">--messages-per-conn=<replaceable>N</replaceable></arg>
+ <arg choice="opt">--no-reply</arg>
+ <arg choice="opt">--queue=<replaceable>N</replaceable></arg>
+ <arg choice="opt">--seed=<replaceable>SEED</replaceable></arg>
+ <group choice="opt">
+ <arg choice="plain">--string</arg>
+ <arg choice="plain">--bytes</arg>
+ <arg choice="plain">--empty</arg>
+ </group>
+ <group choice="opt">
+ <arg choice="plain">--payload=<replaceable>S</replaceable></arg>
+ <arg choice="plain">--stdin</arg>
+ <arg choice="plain">--message-stdin</arg>
+ <arg choice="plain">--random-size</arg>
+ </group>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="description">
+ <title>DESCRIPTION</title>
+ <para><command>dbus-test-tool</command> is a multi-purpose tool
+ for debugging and profiling D-Bus.</para>
+
+ <para><command>dbus-test-tool black-hole</command>
+ connects to D-Bus, optionally requests a name, then does not
+ reply to messages. It normally reads and discards messages from
+ its D-Bus socket, but can be configured to sleep forever without
+ reading.</para>
+
+ <para><command>dbus-test-tool echo</command>
+ connects to D-Bus, optionally requests a name, then sends back an
+ empty reply to every method call, after an optional delay.</para>
+
+ <para><command>dbus-test-tool spam</command>
+ connects to D-Bus and makes repeated method calls,
+ normally named <literal>com.example.Spam</literal>.</para>
+ </refsect1>
+
+ <refsect1 id="options">
+ <title>OPTIONS</title>
+ <refsect2>
+ <title>Common options</title>
+ <variablelist remap="TP">
+
+ <varlistentry>
+ <term><option>--session</option></term>
+ <listitem>
+ <para>Connect to the session bus. This is the default.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--system</option></term>
+ <listitem>
+ <para>Connect to the system bus.</para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect2>
+
+ <refsect2>
+ <title>black-hole mode</title>
+ <variablelist remap="TP">
+
+ <varlistentry>
+ <term><option>--name=</option><replaceable>NAME</replaceable></term>
+ <listitem>
+ <para>Before proceeding, request ownership of the well-known
+ bus name <replaceable>NAME</replaceable>, for example
+ <literal>com.example.NoReply</literal>. By default,
+ no name is requested, and the tool can only be addressed by
+ a unique bus name such as <literal>:1.23</literal>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--no-read</option></term>
+ <listitem>
+ <para>Do not read from the D-Bus socket.</para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect2>
+
+ <refsect2>
+ <title>echo mode</title>
+ <variablelist remap="TP">
+
+ <varlistentry>
+ <term><option>--name=</option><replaceable>NAME</replaceable></term>
+ <listitem>
+ <para>Before proceeding, request ownership of the well-known
+ bus name <replaceable>NAME</replaceable>, for example
+ <literal>com.example.Echo</literal>. By default,
+ no name is requested, and the tool can only be addressed by
+ a unique bus name such as <literal>:1.23</literal>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--sleep=</option><replaceable>MS</replaceable></term>
+ <listitem>
+ <para>Block for <replaceable>MS</replaceable> milliseconds
+ before replying to a method call.</para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect2>
+
+ <refsect2>
+ <title>spam mode</title>
+ <variablelist remap="TP">
+
+ <varlistentry>
+ <term><option>--dest=</option><replaceable>NAME</replaceable></term>
+ <listitem>
+ <para>Send method calls to the well-known or unique
+ bus name <replaceable>NAME</replaceable>.
+ The default is the dbus-daemon,
+ <literal>org.freedesktop.DBus</literal>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--count=</option><replaceable>N</replaceable></term>
+ <listitem>
+ <para>Send <replaceable>N</replaceable> method calls in total.
+ The default is 1.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--queue=</option><replaceable>N</replaceable></term>
+ <listitem>
+ <para>Send <replaceable>N</replaceable> method calls before
+ waiting for any replies, then send one new call per reply
+ received, keeping <replaceable>N</replaceable> method calls
+ "in flight" at all times until the number of messages specified
+ with the <option>--count</option> option have been sent.
+ The default is 1, unless <option>--flood</option>
+ is used.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--flood</option></term>
+ <listitem>
+ <para>Send all messages without waiting for a reply,
+ equivalent to <option>--queue</option> with an arbitrarily
+ large <replaceable>N</replaceable>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--no-reply</option></term>
+ <listitem>
+ <para>Set the "no reply desired" flag on the messages.
+ This implies <option>--flood</option>, since it disables
+ the replies that would be used for a finite
+ <option>--queue</option> length.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--messages-per-conn=</option><replaceable>N</replaceable></term>
+ <listitem>
+ <para>If given, send <replaceable>N</replaceable> method calls
+ on the same connection, then disconnect and reconnect.
+ The default is to use the same connection for all method
+ calls.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--string</option></term>
+ <listitem>
+ <para>The payload of each message is a UTF-8 string. This is the
+ default. The actual string used is given by the
+ <option>--payload</option> or <option>--stdin</option>
+ option, defaulting to "hello, world!".</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--bytes</option></term>
+ <listitem>
+ <para>The payload of each message is a byte-array.
+ The actual bytes used are given by the
+ <option>--payload</option> or <option>--stdin</option>
+ option, defaulting to the ASCII encoding of
+ "hello, world!".</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--empty</option></term>
+ <listitem>
+ <para>The messages have no payload.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--payload=</option><replaceable>S</replaceable></term>
+ <listitem>
+ <para>Use <replaceable>S</replaceable> as the
+ <option>--string</option> or <option>--bytes</option>
+ in the messages. The default is "hello, world!".</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--stdin</option></term>
+ <listitem>
+ <para>Read from standard input until end-of-file is reached,
+ and use that as the <option>--string</option> or
+ <option>--bytes</option> in the messages.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--message-stdin</option></term>
+ <listitem>
+ <para>Read a complete binary D-Bus method call message from
+ standard input, and use that for each method call.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--random-size</option></term>
+ <listitem>
+ <para>Read whitespace-separated ASCII decimal numbers from
+ standard input, choose one at random for each message,
+ and send a message whose payload is a string of that
+ length.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--seed=</option><replaceable>SEED</replaceable></term>
+ <listitem>
+ <para>Use <replaceable>SEED</replaceable> as the seed
+ for the pseudorandom number generator, to have somewhat
+ repeatable sequences of random messages.</para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect2>
+ </refsect1>
+
+ <refsect1 id="bugs">
+ <title>BUGS</title>
+ <para>Please send bug reports to the D-Bus bug tracker or mailing list.
+ See <ulink url="http://www.freedesktop.org/software/dbus/">http://www.freedesktop.org/software/dbus/</ulink>.</para>
+ </refsect1>
+
+ <refsect1 id="see_also">
+ <title>SEE ALSO</title>
+ <para><citerefentry><refentrytitle>dbus-send</refentrytitle><manvolnum>1</manvolnum></citerefentry></para>
+ </refsect1>
+</refentry>
diff --git a/doc/dbus-tutorial.xml b/doc/dbus-tutorial.xml
index c7580d15..c4d9504e 100644
--- a/doc/dbus-tutorial.xml
+++ b/doc/dbus-tutorial.xml
@@ -704,939 +704,19 @@
</sect1>
<sect1 id="glib-client">
- <title>GLib API: Using Remote Objects</title>
-
- <para>
- The GLib binding is defined in the header file
- <literal>&lt;dbus/dbus-glib.h&gt;</literal>.
- </para>
-
- <sect2 id="glib-typemappings">
- <title>D-Bus - GLib type mappings</title>
- <para>
- The heart of the GLib bindings for D-Bus is the mapping it
- provides between D-Bus "type signatures" and GLib types
- (<literal>GType</literal>). The D-Bus type system is composed of
- a number of "basic" types, along with several "container" types.
- </para>
- <sect3 id="glib-basic-typemappings">
- <title>Basic type mappings</title>
- <para>
- Below is a list of the basic types, along with their associated
- mapping to a <literal>GType</literal>.
- <informaltable>
- <tgroup cols="4">
- <thead>
- <row>
- <entry>D-Bus basic type</entry>
- <entry>GType</entry>
- <entry>Free function</entry>
- <entry>Notes</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><literal>BYTE</literal></entry>
- <entry><literal>G_TYPE_UCHAR</literal></entry>
- <entry></entry>
- <entry></entry>
- </row><row>
- <entry><literal>BOOLEAN</literal></entry>
- <entry><literal>G_TYPE_BOOLEAN</literal></entry>
- <entry></entry>
- <entry></entry>
- </row><row>
- <entry><literal>INT16</literal></entry>
- <entry><literal>G_TYPE_INT</literal></entry>
- <entry></entry>
- <entry>Will be changed to a <literal>G_TYPE_INT16</literal> once GLib has it</entry>
- </row><row>
- <entry><literal>UINT16</literal></entry>
- <entry><literal>G_TYPE_UINT</literal></entry>
- <entry></entry>
- <entry>Will be changed to a <literal>G_TYPE_UINT16</literal> once GLib has it</entry>
- </row><row>
- <entry><literal>INT32</literal></entry>
- <entry><literal>G_TYPE_INT</literal></entry>
- <entry></entry>
- <entry>Will be changed to a <literal>G_TYPE_INT32</literal> once GLib has it</entry>
- </row><row>
- <entry><literal>UINT32</literal></entry>
- <entry><literal>G_TYPE_UINT</literal></entry>
- <entry></entry>
- <entry>Will be changed to a <literal>G_TYPE_UINT32</literal> once GLib has it</entry>
- </row><row>
- <entry><literal>INT64</literal></entry>
- <entry><literal>G_TYPE_GINT64</literal></entry>
- <entry></entry>
- <entry></entry>
- </row><row>
- <entry><literal>UINT64</literal></entry>
- <entry><literal>G_TYPE_GUINT64</literal></entry>
- <entry></entry>
- <entry></entry>
- </row><row>
- <entry><literal>DOUBLE</literal></entry>
- <entry><literal>G_TYPE_DOUBLE</literal></entry>
- <entry></entry>
- <entry></entry>
- </row><row>
- <entry><literal>STRING</literal></entry>
- <entry><literal>G_TYPE_STRING</literal></entry>
- <entry><literal>g_free</literal></entry>
- <entry></entry>
- </row><row>
- <entry><literal>OBJECT_PATH</literal></entry>
- <entry><literal>DBUS_TYPE_G_PROXY</literal></entry>
- <entry><literal>g_object_unref</literal></entry>
- <entry>The returned proxy does not have an interface set; use <literal>dbus_g_proxy_set_interface</literal> to invoke methods</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- As you can see, the basic mapping is fairly straightforward.
- </para>
- </sect3>
- <sect3 id="glib-container-typemappings">
- <title>Container type mappings</title>
- <para>
- The D-Bus type system also has a number of "container"
- types, such as <literal>DBUS_TYPE_ARRAY</literal> and
- <literal>DBUS_TYPE_STRUCT</literal>. The D-Bus type system
- is fully recursive, so one can for example have an array of
- array of strings (i.e. type signature
- <literal>aas</literal>).
- </para>
- <para>
- 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 <literal>DBUS_TYPE_STRUCT</literal>, or a
- <literal>DBUS_TYPE_ARRAY</literal> 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".
- </para>
- <para>
- First, D-Bus type signatures which have an "obvious"
- corresponding built-in GLib type are mapped using that type:
- <informaltable>
- <tgroup cols="6">
- <thead>
- <row>
- <entry>D-Bus type signature</entry>
- <entry>Description</entry>
- <entry>GType</entry>
- <entry>C typedef</entry>
- <entry>Free function</entry>
- <entry>Notes</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><literal>as</literal></entry>
- <entry>Array of strings</entry>
- <entry><literal>G_TYPE_STRV</literal></entry>
- <entry><literal>char **</literal></entry>
- <entry><literal>g_strfreev</literal></entry>
- <entry></entry>
- </row><row>
- <entry><literal>v</literal></entry>
- <entry>Generic value container</entry>
- <entry><literal>G_TYPE_VALUE</literal></entry>
- <entry><literal>GValue *</literal></entry>
- <entry><literal>g_value_unset</literal></entry>
- <entry>The calling conventions for values expect that method callers have allocated return values; see below.</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </para>
- <para>
- The next most common recursive type signatures are arrays of
- basic values. The most obvious mapping for arrays of basic
- types is a <literal>GArray</literal>. Now, GLib does not
- provide a builtin <literal>GType</literal> for
- <literal>GArray</literal>. 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.
- </para>
- <para>
- 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.
- <informaltable>
- <tgroup cols="6">
- <thead>
- <row>
- <entry>D-Bus type signature</entry>
- <entry>Description</entry>
- <entry>GType</entry>
- <entry>C typedef</entry>
- <entry>Free function</entry>
- <entry>Notes</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><literal>ay</literal></entry>
- <entry>Array of bytes</entry>
- <entry><literal>DBUS_TYPE_G_BYTE_ARRAY</literal></entry>
- <entry><literal>GArray *</literal></entry>
- <entry>g_array_free</entry>
- <entry></entry>
- </row>
- <row>
- <entry><literal>au</literal></entry>
- <entry>Array of uint</entry>
- <entry><literal>DBUS_TYPE_G_UINT_ARRAY</literal></entry>
- <entry><literal>GArray *</literal></entry>
- <entry>g_array_free</entry>
- <entry></entry>
- </row>
- <row>
- <entry><literal>ai</literal></entry>
- <entry>Array of int</entry>
- <entry><literal>DBUS_TYPE_G_INT_ARRAY</literal></entry>
- <entry><literal>GArray *</literal></entry>
- <entry>g_array_free</entry>
- <entry></entry>
- </row>
- <row>
- <entry><literal>ax</literal></entry>
- <entry>Array of int64</entry>
- <entry><literal>DBUS_TYPE_G_INT64_ARRAY</literal></entry>
- <entry><literal>GArray *</literal></entry>
- <entry>g_array_free</entry>
- <entry></entry>
- </row>
- <row>
- <entry><literal>at</literal></entry>
- <entry>Array of uint64</entry>
- <entry><literal>DBUS_TYPE_G_UINT64_ARRAY</literal></entry>
- <entry><literal>GArray *</literal></entry>
- <entry>g_array_free</entry>
- <entry></entry>
- </row>
- <row>
- <entry><literal>ad</literal></entry>
- <entry>Array of double</entry>
- <entry><literal>DBUS_TYPE_G_DOUBLE_ARRAY</literal></entry>
- <entry><literal>GArray *</literal></entry>
- <entry>g_array_free</entry>
- <entry></entry>
- </row>
- <row>
- <entry><literal>ab</literal></entry>
- <entry>Array of boolean</entry>
- <entry><literal>DBUS_TYPE_G_BOOLEAN_ARRAY</literal></entry>
- <entry><literal>GArray *</literal></entry>
- <entry>g_array_free</entry>
- <entry></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </para>
- <para>
- 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 <literal>GType</literal> 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.
- </para>
- <para>
- At present, only strings are supported. Work is in progress to
- include more types.
- <informaltable>
- <tgroup cols="6">
- <thead>
- <row>
- <entry>D-Bus type signature</entry>
- <entry>Description</entry>
- <entry>GType</entry>
- <entry>C typedef</entry>
- <entry>Free function</entry>
- <entry>Notes</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><literal>a{ss}</literal></entry>
- <entry>Dictionary mapping strings to strings</entry>
- <entry><literal>DBUS_TYPE_G_STRING_STRING_HASHTABLE</literal></entry>
- <entry><literal>GHashTable *</literal></entry>
- <entry>g_hash_table_destroy</entry>
- <entry></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </para>
- </sect3>
- <sect3 id="glib-generic-typemappings">
- <title>Arbitrarily recursive type mappings</title>
- <para>
- 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
- <literal>DBusGValue</literal> which acts as a kind of special
- variant value which may be iterated over manually. The
- <literal>GType</literal> associated is
- <literal>DBUS_TYPE_G_VALUE</literal>.
- </para>
- <para>
- TODO insert usage of <literal>DBUS_TYPE_G_VALUE</literal> here.
- </para>
- </sect3>
- </sect2>
- <sect2 id="sample-program-1">
- <title>A sample program</title>
- <para>Here is a D-Bus program using the GLib bindings.
-<programlisting>
-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,
- &amp;error);
- if (connection == NULL)
- {
- g_printerr ("Failed to open connection to bus: %s\n",
- error-&gt;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", &amp;error, G_TYPE_INVALID,
- G_TYPE_STRV, &amp;name_list, G_TYPE_INVALID))
- {
- /* Just do demonstrate remote exceptions versus regular GError */
- if (error->domain == DBUS_GERROR &amp;&amp; error->code == DBUS_GERROR_REMOTE_EXCEPTION)
- g_printerr ("Caught remote method exception %s: %s",
- dbus_g_error_get_name (error),
- error-&gt;message);
- else
- g_printerr ("Error: %s\n", error-&gt;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;
-}
-</programlisting>
- </para>
- </sect2>
- <sect2 id="glib-program-setup">
- <title>Program initalization</title>
- <para>
- A connection to the bus is acquired using
- <literal>dbus_g_bus_get</literal>. Next, a proxy
- is created for the object "/org/freedesktop/DBus" with
- interface <literal>org.freedesktop.DBus</literal>
- on the service <literal>org.freedesktop.DBus</literal>.
- This is a proxy for the message bus itself.
- </para>
- </sect2>
- <sect2 id="glib-method-invocation">
- <title>Understanding method invocation</title>
- <para>
- You have a number of choices for method invocation. First, as
- used above, <literal>dbus_g_proxy_call</literal> 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 <literal>G_TYPE_INVALID</literal>.
- Next, pointers to return values are specified, followed again
- by <literal>G_TYPE_INVALID</literal>.
- </para>
- <para>
- To invoke a method asynchronously, use
- <literal>dbus_g_proxy_begin_call</literal>. This returns a
- <literal>DBusGPendingCall</literal> object; you may then set a
- notification function using
- <literal>dbus_g_pending_call_set_notify</literal>.
- </para>
- </sect2>
- <sect2 id="glib-signal-connection">
- <title>Connecting to object signals</title>
- <para>
- You may connect to signals using
- <literal>dbus_g_proxy_add_signal</literal> and
- <literal>dbus_g_proxy_connect_signal</literal>. You must
- invoke <literal>dbus_g_proxy_add_signal</literal> to specify
- the signature of your signal handlers; you may then invoke
- <literal>dbus_g_proxy_connect_signal</literal> multiple times.
- </para>
- <para>
- 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
- <application>glib-genmarshal</application>, and then register
- it using <literal>dbus_g_object_register_marshaller</literal>.
- </para>
- </sect2>
- <sect2 id="glib-error-handling">
- <title>Error handling and remote exceptions</title>
- <para>
- All of the GLib binding methods such as
- <literal>dbus_g_proxy_end_call</literal> return a
- <literal>GError</literal>. This <literal>GError</literal> can
- represent two different things:
- <itemizedlist>
- <listitem>
- <para>
- 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
- <literal>DBUS_GERROR</literal>, and a corresponding code
- such as <literal>DBUS_GERROR_NO_MEMORY</literal>. It will
- not be typical for applications to handle these errors
- specifically.
- </para>
- </listitem>
- <listitem>
- <para>
- 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 <literal>GError</literal>, but some
- special rules apply.
- </para>
- <para>
- The set error will have the domain
- <literal>DBUS_GERROR</literal> as above, and will also
- have the code
- <literal>DBUS_GERROR_REMOTE_EXCEPTION</literal>. In order
- to access the remote exception name, you must use a
- special accessor, such as
- <literal>dbus_g_error_has_name</literal> or
- <literal>dbus_g_error_get_name</literal>. The remote
- exception detailed message is accessible via the regular
- GError <literal>message</literal> member.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- </sect2>
- <sect2 id="glib-more-examples">
- <title>More examples of method invocation</title>
- <sect3 id="glib-sending-stuff">
- <title>Sending an integer and string, receiving an array of bytes</title>
- <para>
-<programlisting>
- GArray *arr;
-
- error = NULL;
- if (!dbus_g_proxy_call (proxy, "Foobar", &amp;error,
- G_TYPE_INT, 42, G_TYPE_STRING, "hello",
- G_TYPE_INVALID,
- DBUS_TYPE_G_UCHAR_ARRAY, &amp;arr, G_TYPE_INVALID))
- {
- /* Handle error */
- }
- g_assert (arr != NULL);
- printf ("got back %u values", arr->len);
-</programlisting>
- </para>
- </sect3>
- <sect3 id="glib-sending-hash">
- <title>Sending a GHashTable</title>
- <para>
-<programlisting>
- 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", &amp;error,
- DBUS_TYPE_G_STRING_STRING_HASH, hash, G_TYPE_INVALID,
- G_TYPE_UINT, &amp;ret, G_TYPE_INVALID))
- {
- /* Handle error */
- }
- g_assert (ret == 2);
- g_hash_table_destroy (hash);
-</programlisting>
- </para>
- </sect3>
- <sect3 id="glib-receiving-bool-int">
- <title>Receiving a boolean and a string</title>
- <para>
-<programlisting>
- gboolean boolret;
- char *strret;
-
- error = NULL;
- if (!dbus_g_proxy_call (proxy, "GetStuff", &amp;error,
- G_TYPE_INVALID,
- G_TYPE_BOOLEAN, &amp;boolret,
- G_TYPE_STRING, &amp;strret,
- G_TYPE_INVALID))
- {
- /* Handle error */
- }
- printf ("%s %s", boolret ? "TRUE" : "FALSE", strret);
- g_free (strret);
-</programlisting>
- </para>
- </sect3>
- <sect3 id="glib-sending-str-arrays">
- <title>Sending two arrays of strings</title>
- <para>
-<programlisting>
- /* 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", &amp;error,
- G_TYPE_STRV, strs_static_p,
- G_TYPE_STRV, strs_dynamic,
- G_TYPE_INVALID,
- G_TYPE_INVALID))
- {
- /* Handle error */
- }
- g_strfreev (strs_dynamic);
-</programlisting>
- </para>
- </sect3>
- <sect3 id="glib-getting-str-array">
- <title>Sending a boolean, receiving an array of strings</title>
- <para>
-<programlisting>
- char **strs;
- char **strs_p;
- gboolean blah;
-
- error = NULL;
- blah = TRUE;
- if (!dbus_g_proxy_call (proxy, "GetStrs", &amp;error,
- G_TYPE_BOOLEAN, blah,
- G_TYPE_INVALID,
- G_TYPE_STRV, &amp;strs,
- G_TYPE_INVALID))
- {
- /* Handle error */
- }
- for (strs_p = strs; *strs_p; strs_p++)
- printf ("got string: \"%s\"", *strs_p);
- g_strfreev (strs);
-</programlisting>
- </para>
- </sect3>
- <sect3 id="glib-sending-variant">
- <title>Sending a variant</title>
- <para>
-<programlisting>
- GValue val = {0, };
-
- g_value_init (&amp;val, G_TYPE_STRING);
- g_value_set_string (&amp;val, "hello world");
-
- error = NULL;
- if (!dbus_g_proxy_call (proxy, "SendVariant", &amp;error,
- G_TYPE_VALUE, &amp;val, G_TYPE_INVALID,
- G_TYPE_INVALID))
- {
- /* Handle error */
- }
- g_assert (ret == 2);
- g_value_unset (&amp;val);
-</programlisting>
- </para>
- </sect3>
- <sect3 id="glib-receiving-variant">
- <title>Receiving a variant</title>
- <para>
-<programlisting>
- GValue val = {0, };
-
- error = NULL;
- if (!dbus_g_proxy_call (proxy, "GetVariant", &amp;error, G_TYPE_INVALID,
- G_TYPE_VALUE, &amp;val, G_TYPE_INVALID))
- {
- /* Handle error */
- }
- if (G_VALUE_TYPE (&amp;val) == G_TYPE_STRING)
- printf ("%s\n", g_value_get_string (&amp;val));
- else if (G_VALUE_TYPE (&amp;val) == G_TYPE_INT)
- printf ("%d\n", g_value_get_int (&amp;val));
- else
- ...
- g_value_unset (&amp;val);
-</programlisting>
- </para>
- </sect3>
- </sect2>
-
- <sect2 id="glib-generated-bindings">
- <title>Generated Bindings</title>
- <para>
- By using the Introspection XML files, convenient client-side bindings
- can be automatically created to ease the use of a remote DBus object.
- </para>
- <para>
- Here is a sample XML file which describes an object that exposes
- one method, named <literal>ManyArgs</literal>.
- <programlisting>
-&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
-&lt;node name="/com/example/MyObject"&gt;
- &lt;interface name="com.example.MyObject"&gt;
- &lt;method name="ManyArgs"&gt;
- &lt;arg type="u" name="x" direction="in" /&gt;
- &lt;arg type="s" name="str" direction="in" /&gt;
- &lt;arg type="d" name="trouble" direction="in" /&gt;
- &lt;arg type="d" name="d_ret" direction="out" /&gt;
- &lt;arg type="s" name="str_ret" direction="out" /&gt;
- &lt;/method&gt;
- &lt;/interface&gt;
-&lt;/node&gt;
-</programlisting>
- </para>
- <para>
- Run <literal>dbus-binding-tool --mode=glib-client
- <replaceable>FILENAME</replaceable> &gt;
- <replaceable>HEADER_NAME</replaceable></literal> to generate the header
- file. For example: <command>dbus-binding-tool --mode=glib-client
- my-object.xml &gt; my-object-bindings.h</command>. This will generate
- inline functions with the following prototypes:
- <programlisting>
-/* 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);
-</programlisting>
- The first argument in all functions is a <literal>DBusGProxy
- *</literal>, which you should create with the usual
- <literal>dbus_g_proxy_new_*</literal> functions. Following that are the
- "in" arguments, and then either the "out" arguments and a
- <literal>GError *</literal> 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
- <literal>DBusGProxy *</literal>, the returned "out" arguments, an
- <literal>GError *</literal> which is set if there was an error otherwise
- <literal>NULL</literal>, and the user data.
- </para>
- <para>
- As with the server-side bindings support (see <xref
- linkend="glib-server"/>), the exact behaviour of the client-side
- bindings can be manipulated using "annotations". Currently the only
- annotation used by the client bindings is
- <literal>org.freedesktop.DBus.GLib.NoReply</literal>, 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.
- </para>
- </sect2>
- </sect1>
-
- <sect1 id="glib-server">
- <title>GLib API: Implementing Objects</title>
+ <title>GLib APIs</title>
<para>
- 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.
+ The recommended GLib API for D-Bus is GDBus, which has been
+ distributed with GLib since version 2.26. It is not documented here.
+ See <ulink url="https://developer.gnome.org/gio/stable/gdbus-convenience.html">the
+ GLib documentation</ulink> for details of how to use GDBus.
</para>
- <para>
- Here is a sample XML file which describes an object that exposes
- one method, named <literal>ManyArgs</literal>.
-<programlisting>
-&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
-
-&lt;node name="/com/example/MyObject"&gt;
- &lt;interface name="com.example.MyObject"&gt;
- &lt;annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object"/&gt;
- &lt;method name="ManyArgs"&gt;
- &lt;!-- This is optional, and in this case is redunundant --&gt;
- &lt;annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_many_args"/&gt;
- &lt;arg type="u" name="x" direction="in" /&gt;
- &lt;arg type="s" name="str" direction="in" /&gt;
- &lt;arg type="d" name="trouble" direction="in" /&gt;
- &lt;arg type="d" name="d_ret" direction="out" /&gt;
- &lt;arg type="s" name="str_ret" direction="out" /&gt;
- &lt;/method&gt;
- &lt;/interface&gt;
-&lt;/node&gt;
-</programlisting>
- </para>
<para>
- 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
- (<literal>my_object</literal>). In addition, if particular
- methods symbol names deviate from C convention
- (i.e. <literal>ManyArgs</literal> -&gt;
- <literal>many_args</literal>), you may specify an annotation
- giving the C symbol.
+ An older API, dbus-glib, also exists. It is deprecated and should
+ not be used in new code. Whenever possible, porting existing code
+ from dbus-glib to GDBus is also recommended.
</para>
- <para>
- Once you have written this XML, run <literal>dbus-binding-tool --mode=glib-server <replaceable>FILENAME</replaceable> &gt; <replaceable>HEADER_NAME</replaceable>.</literal> to
- generate a header file. For example: <command>dbus-binding-tool --mode=glib-server my-object.xml &gt; my-object-glue.h</command>.
- </para>
- <para>
- Next, include the generated header in your program, and invoke
- <literal>dbus_g_object_class_install_info</literal> in the class
- initializer, passing the object class and "object info" included in the
- header. For example:
- <programlisting>
- dbus_g_object_type_install_info (COM_FOO_TYPE_MY_OBJECT, &amp;com_foo_my_object_info);
- </programlisting>
- This should be done exactly once per object class.
- </para>
- <para>
- To actually implement the method, just define a C function named e.g.
- <literal>my_object_many_args</literal> in the same file as the info
- header is included. At the moment, it is required that this function
- conform to the following rules:
- <itemizedlist>
- <listitem>
- <para>
- The function must return a value of type <literal>gboolean</literal>;
- <literal>TRUE</literal> on success, and <literal>FALSE</literal>
- otherwise.
- </para>
- </listitem>
- <listitem>
- <para>
- The first parameter is a pointer to an instance of the object.
- </para>
- </listitem>
- <listitem>
- <para>
- Following the object instance pointer are the method
- input values.
- </para>
- </listitem>
- <listitem>
- <para>
- Following the input values are pointers to return values.
- </para>
- </listitem>
- <listitem>
- <para>
- The final parameter must be a <literal>GError **</literal>.
- If the function returns <literal>FALSE</literal> for an
- error, the error parameter must be initalized with
- <literal>g_set_error</literal>.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- Finally, you can export an object using <literal>dbus_g_connection_register_g_object</literal>. For example:
- <programlisting>
- dbus_g_connection_register_g_object (connection,
- "/com/foo/MyObject",
- obj);
- </programlisting>
- </para>
-
- <sect2 id="glib-annotations">
- <title>Server-side Annotations</title>
- <para>
- There are several annotations that are used when generating the
- server-side bindings. The most common annotation is
- <literal>org.freedesktop.DBus.GLib.CSymbol</literal> but there are other
- annotations which are often useful.
- <variablelist>
- <varlistentry>
- <term><literal>org.freedesktop.DBus.GLib.CSymbol</literal></term>
- <listitem>
- <para>
- 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.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>org.freedesktop.DBus.GLib.Async</literal></term>
- <listitem>
- <para>
- 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.
- </para>
- <para>
- When a method is asynchronous, the function prototype is
- different. It is required that the function conform to the
- following rules:
- <itemizedlist>
- <listitem>
- <para>
- The function must return a value of type <literal>gboolean</literal>;
- <literal>TRUE</literal> on success, and <literal>FALSE</literal>
- otherwise. TODO: the return value is currently ignored.
- </para>
- </listitem>
- <listitem>
- <para>
- The first parameter is a pointer to an instance of the object.
- </para>
- </listitem>
- <listitem>
- <para>
- Following the object instance pointer are the method
- input values.
- </para>
- </listitem>
- <listitem>
- <para>
- The final parameter must be a
- <literal>DBusGMethodInvocation *</literal>. This is used
- when sending the response message back to the client, by
- calling <literal>dbus_g_method_return</literal> or
- <literal>dbus_g_method_return_error</literal>.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>org.freedesktop.DBus.GLib.Const</literal></term>
- <listitem>
- <para>This attribute can only be applied to "out"
- <literal>&lt;arg&gt;</literal> nodes, and specifies that the
- parameter isn't being copied when returned. For example, this
- turns a 's' argument from a <literal>char **</literal> to a
- <literal>const char **</literal>, and results in the argument not
- being freed by DBus after the message is sent.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>org.freedesktop.DBus.GLib.ReturnVal</literal></term>
- <listitem>
- <para>
- This attribute can only be applied to "out"
- <literal>&lt;arg&gt;</literal> nodes, and alters the expected
- function signature. It currently can be set to two values:
- <literal>""</literal> or <literal>"error"</literal>. 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 <literal>GError
- *</literal> 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 <literal>"error"</literal>, then the
- final argument is a <literal>GError *</literal> as usual.
- </para>
- <para>
- Some examples to demonstrate the usage. This introspection XML:
- <programlisting>
-&lt;method name="Increment"&gt;
- &lt;arg type="u" name="x" /&gt;
- &lt;arg type="u" direction="out" /&gt;
-&lt;/method&gt;
- </programlisting>
- Expects the following function declaration:
- <programlisting>
-gboolean
-my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error);
- </programlisting>
- </para>
- <para>
- This introspection XML:
- <programlisting>
-&lt;method name="IncrementRetval"&gt;
- &lt;arg type="u" name="x" /&gt;
- &lt;arg type="u" direction="out" &gt;
- &lt;annotation name="org.freedesktop.DBus.GLib.ReturnVal" value=""/&gt;
- &lt;/arg&gt;
-&lt;/method&gt;
- </programlisting>
- Expects the following function declaration:
- <programlisting>
-gint32
-my_object_increment_retval (MyObject *obj, gint32 x)
- </programlisting>
- </para>
- <para>
- This introspection XML:
- <programlisting>
-&lt;method name="IncrementRetvalError"&gt;
- &lt;arg type="u" name="x" /&gt;
- &lt;arg type="u" direction="out" &gt;
- &lt;annotation name="org.freedesktop.DBus.GLib.ReturnVal" value="error"/&gt;
- &lt;/arg&gt;
-&lt;/method&gt;
- </programlisting>
- Expects the following function declaration:
- <programlisting>
-gint32
-my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error)
- </programlisting>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </para>
- </sect2>
</sect1>
<sect1 id="python-client">
@@ -1650,18 +730,12 @@ my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error)
</sect1>
<sect1 id="qt-client">
- <title>Qt API: Using Remote Objects</title>
- <para>
-
- The Qt bindings are not yet documented.
-
- </para>
- </sect1>
-
- <sect1 id="qt-server">
- <title>Qt API: Implementing Objects</title>
+ <title>Qt API</title>
<para>
- The Qt bindings are not yet documented.
+ The Qt binding for libdbus, QtDBus, has been distributed with Qt
+ since version 4.2. It is not documented here. See
+ <ulink url="http://qt-project.org/doc/qt-5/qtdbus-index.html">the Qt
+ documentation</ulink> for details of how to use QtDBus.
</para>
</sect1>
</article>
diff --git a/doc/dbus-update-activation-environment.1.xml.in b/doc/dbus-update-activation-environment.1.xml.in
new file mode 100644
index 00000000..8a495df6
--- /dev/null
+++ b/doc/dbus-update-activation-environment.1.xml.in
@@ -0,0 +1,213 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
+<refentry id="dbus-update-activation-environment.1">
+ <refentryinfo>
+ <copyright>
+ <year>2015</year>
+ <holder>Collabora Ltd.</holder>
+ </copyright>
+ <legalnotice>
+ <para>This man page is distributed under the same terms as
+ dbus-update-activation-environment (MIT/X11). There is NO WARRANTY,
+ to the extent permitted by law.</para>
+ </legalnotice>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>dbus-update-activation-environment</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="manual">User Commands</refmiscinfo>
+ <refmiscinfo class="source">D-Bus</refmiscinfo>
+ <refmiscinfo class="version">@DBUS_VERSION@</refmiscinfo>
+ </refmeta>
+ <refnamediv>
+ <refname>dbus-update-activation-environment</refname>
+ <refpurpose>update environment used for D-Bus session services</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv id="synopsis">
+ <cmdsynopsis>
+ <command>dbus-update-activation-environment</command>
+ <arg choice="opt">--systemd</arg>
+ <arg choice="opt">--verbose</arg>
+ <group choice="plain">
+ <arg choice="plain">--all</arg>
+ <arg choice="plain" rep="repeat"><replaceable>VAR</replaceable></arg>
+ <arg choice="plain" rep="repeat"><replaceable>VAR</replaceable>=<replaceable>VAL</replaceable></arg>
+ </group>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="description">
+ <title>DESCRIPTION</title>
+ <para><command>dbus-update-activation-environment</command>
+ updates the list of environment variables used by
+ <command>dbus-daemon --session</command>
+ when it activates session services without using
+ <command>systemd</command>.</para>
+
+ <para>With the <option>--systemd</option> option,
+ if an instance of <command>systemd --user</command> is
+ available on D-Bus, it also updates the list of environment variables
+ used by <command>systemd --user</command>
+ when it activates user services, including D-Bus session services
+ for which <command>dbus-daemon</command> has been configured to
+ delegate activation to <command>systemd</command>.
+ This is very similar to the <option>import-environment</option>
+ command provided by
+ <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>).</para>
+
+ <para>Variables that are special to <command>dbus-daemon</command>
+ or <command>systemd</command> may be set, but their values will
+ be overridden when a service is started. For instance, it is
+ not useful to add <envar>DBUS_SESSION_BUS_ADDRESS</envar> to
+ <command>dbus-daemon</command>'s activation environment,
+ although it might still be useful to add it to
+ <command>systemd</command>'s activation environment.</para>
+ </refsect1>
+
+ <refsect1 id="options">
+ <title>OPTIONS</title>
+ <variablelist remap="TP">
+
+ <varlistentry>
+ <term><option>--all</option></term>
+ <listitem>
+ <para>Set all environment variables present in
+ the environment used by
+ <command>dbus-update-activation-environment</command>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--systemd</option></term>
+ <listitem>
+ <para>Set environment variables for systemd user services as well as
+ for traditional D-Bus session services.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--verbose</option></term>
+ <listitem>
+ <para>Output messages to standard error explaining what
+ dbus-update-activation-environment is doing.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable>VAR</replaceable></term>
+ <listitem>
+ <para>If <replaceable>VAR</replaceable> is present in the
+ environment of <command>dbus-update-activation-environment</command>,
+ set it to the same value for D-Bus services. Its value must be
+ UTF-8 (if not, it is skipped with a warning). If
+ <replaceable>VAR</replaceable> is not present
+ in the environment, this argument is silently ignored.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable>VAR</replaceable>=<replaceable>VAL</replaceable></term>
+ <listitem>
+ <para>Set <replaceable>VAR</replaceable> to <replaceable>VAL</replaceable>,
+ which must be UTF-8.</para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect1>
+
+ <refsect1 id="examples">
+ <title>EXAMPLES</title>
+ <para>
+ <command>dbus-update-activation-environment</command> is
+ primarily designed to be used in Linux distributions' X11 session
+ startup scripts, in conjunction with the "user bus" design.
+ </para>
+
+ <para>To propagate <envar>DISPLAY</envar> and <envar>XAUTHORITY</envar>
+ to <command>dbus-daemon</command>
+ and, if present, <command>systemd</command>,
+ and propagate <envar>DBUS_SESSION_BUS_ADDRESS</envar> to
+ <command>systemd</command>:
+ <programlisting language="sh">
+ dbus-update-activation-environment --systemd \
+ DBUS_SESSION_BUS_ADDRESS DISPLAY XAUTHORITY
+ </programlisting>
+ </para>
+
+ <para>To propagate all environment variables except
+ <envar>XDG_SEAT</envar>, <envar>XDG_SESSION_ID</envar>
+ and <envar>XDG_VTNR</envar> to <command>dbus-daemon</command>
+ (and, if present, <command>systemd</command>) for compatibility
+ with legacy X11 session startup scripts:
+ <programlisting language="sh">
+ # in a subshell so the variables remain set in the
+ # parent script
+ (
+ unset XDG_SEAT
+ unset XDG_SESSION_ID
+ unset XDG_VTNR
+
+ dbus-update-activation-environment --systemd --all
+ )
+ </programlisting>
+ </para>
+ </refsect1>
+
+ <refsect1 id="exit_status">
+ <title>EXIT STATUS</title>
+ <para>
+ <command>dbus-update-activation-environment</command>
+ exits with status 0 on success, EX_USAGE (64) on invalid
+ command-line options, EX_OSERR (71) if unable to connect
+ to the session bus, or EX_UNAVAILABLE (69) if unable to
+ set the environment variables. Other nonzero exit codes might be
+ added in future versions.</para>
+ </refsect1>
+
+ <refsect1 id="environment">
+ <title>ENVIRONMENT</title>
+ <para><envar>DBUS_SESSION_BUS_ADDRESS</envar>,
+ <envar>XDG_RUNTIME_DIR</envar> and/or <envar>DISPLAY</envar>
+ are used to find the address of the session bus.</para>
+ </refsect1>
+
+ <refsect1 id="limitations">
+ <title>LIMITATIONS</title>
+ <para>
+ <command>dbus-daemon</command> does not provide a way to unset
+ environment variables after they have been set (although
+ <command>systemd</command> does), so
+ <command>dbus-update-activation-environment</command> does not
+ offer this functionality either.
+ </para>
+
+ <para>
+ POSIX does not specify the encoding of non-ASCII environment variable
+ names or values and allows them to contain any non-zero byte, but
+ neither <command>dbus-daemon</command> nor <command>systemd</command>
+ supports environment variables with non-UTF-8 names or values.
+ Accordingly, <command>dbus-update-activation-environment</command>
+ assumes that any name or value that appears to be valid UTF-8 is
+ intended to be UTF-8, and ignores other names or values with a warning.
+ </para>
+ </refsect1>
+
+ <refsect1 id="bugs">
+ <title>BUGS</title>
+ <para>Please send bug reports to the D-Bus bug tracker or mailing list.
+ See <ulink url="http://www.freedesktop.org/software/dbus/">http://www.freedesktop.org/software/dbus/</ulink>.</para>
+ </refsect1>
+
+ <refsect1 id="see_also">
+ <title>SEE ALSO</title>
+ <para><citerefentry><refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ the <option>import-environment</option> command of
+ <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></para>
+ </refsect1>
+</refentry>
diff --git a/m4/ld-version-script.m4 b/m4/ld-version-script.m4
new file mode 100644
index 00000000..228f52f5
--- /dev/null
+++ b/m4/ld-version-script.m4
@@ -0,0 +1,43 @@
+# ld-version-script.m4 serial 1
+dnl Copyright (C) 2008, 2009 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.
+
+dnl From Simon Josefsson
+
+# FIXME: The test below returns a false positive for mingw
+# cross-compiles, 'local:' statements does not reduce number of
+# exported symbols in a DLL. Use --disable-ld-version-script to work
+# around the problem.
+
+# gl_LD_VERSION_SCRIPT
+# --------------------
+# Check if LD supports linker scripts, and define automake conditional
+# HAVE_LD_VERSION_SCRIPT if so.
+AC_DEFUN([gl_LD_VERSION_SCRIPT],
+[
+ AC_ARG_ENABLE([ld-version-script],
+ AS_HELP_STRING([--enable-ld-version-script],
+ [enable linker version script (default is enabled when possible)]),
+ [have_ld_version_script=$enableval], [])
+ if test -z "$have_ld_version_script"; then
+ AC_MSG_CHECKING([if LD -Wl,--version-script works])
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -Wl,--version-script=conftest.map"
+ cat > conftest.map <<EOF
+VERS_1 {
+ global: sym;
+};
+
+VERS_2 {
+ global: sym;
+} VERS_1;
+EOF
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
+ [have_ld_version_script=yes], [have_ld_version_script=no])
+ rm -f conftest.map
+ LDFLAGS="$save_LDFLAGS"
+ AC_MSG_RESULT($have_ld_version_script)
+ fi
+])
diff --git a/m4/visibility.m4 b/m4/visibility.m4
new file mode 100644
index 00000000..552e3977
--- /dev/null
+++ b/m4/visibility.m4
@@ -0,0 +1,77 @@
+# visibility.m4 serial 5 (gettext-0.18.2)
+dnl Copyright (C) 2005, 2008, 2010-2014 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.
+
+dnl From Bruno Haible.
+
+dnl Tests whether the compiler supports the command-line option
+dnl -fvisibility=hidden and the function and variable attributes
+dnl __attribute__((__visibility__("hidden"))) and
+dnl __attribute__((__visibility__("default"))).
+dnl Does *not* test for __visibility__("protected") - which has tricky
+dnl semantics (see the 'vismain' test in glibc) and does not exist e.g. on
+dnl Mac OS X.
+dnl Does *not* test for __visibility__("internal") - which has processor
+dnl dependent semantics.
+dnl Does *not* test for #pragma GCC visibility push(hidden) - which is
+dnl "really only recommended for legacy code".
+dnl Set the variable CFLAG_VISIBILITY.
+dnl Defines and sets the variable HAVE_VISIBILITY.
+
+AC_DEFUN([gl_VISIBILITY],
+[
+ AC_REQUIRE([AC_PROG_CC])
+ CFLAG_VISIBILITY=
+ HAVE_VISIBILITY=0
+ if test -n "$GCC"; then
+ dnl First, check whether -Werror can be added to the command line, or
+ dnl whether it leads to an error because of some other option that the
+ dnl user has put into $CC $CFLAGS $CPPFLAGS.
+ AC_MSG_CHECKING([whether the -Werror option is usable])
+ AC_CACHE_VAL([gl_cv_cc_vis_werror], [
+ gl_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -Werror"
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([[]], [[]])],
+ [gl_cv_cc_vis_werror=yes],
+ [gl_cv_cc_vis_werror=no])
+ CFLAGS="$gl_save_CFLAGS"])
+ AC_MSG_RESULT([$gl_cv_cc_vis_werror])
+ dnl Now check whether visibility declarations are supported.
+ AC_MSG_CHECKING([for simple visibility declarations])
+ AC_CACHE_VAL([gl_cv_cc_visibility], [
+ gl_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -fvisibility=hidden"
+ dnl We use the option -Werror and a function dummyfunc, because on some
+ dnl platforms (Cygwin 1.7) the use of -fvisibility triggers a warning
+ dnl "visibility attribute not supported in this configuration; ignored"
+ dnl at the first function definition in every compilation unit, and we
+ dnl don't want to use the option in this case.
+ if test $gl_cv_cc_vis_werror = yes; then
+ CFLAGS="$CFLAGS -Werror"
+ fi
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[extern __attribute__((__visibility__("hidden"))) int hiddenvar;
+ extern __attribute__((__visibility__("default"))) int exportedvar;
+ extern __attribute__((__visibility__("hidden"))) int hiddenfunc (void);
+ extern __attribute__((__visibility__("default"))) int exportedfunc (void);
+ void dummyfunc (void) {}
+ ]],
+ [[]])],
+ [gl_cv_cc_visibility=yes],
+ [gl_cv_cc_visibility=no])
+ CFLAGS="$gl_save_CFLAGS"])
+ AC_MSG_RESULT([$gl_cv_cc_visibility])
+ if test $gl_cv_cc_visibility = yes; then
+ CFLAG_VISIBILITY="-fvisibility=hidden"
+ HAVE_VISIBILITY=1
+ fi
+ fi
+ AC_SUBST([CFLAG_VISIBILITY])
+ AC_SUBST([HAVE_VISIBILITY])
+ AC_DEFINE_UNQUOTED([HAVE_VISIBILITY], [$HAVE_VISIBILITY],
+ [Define to 1 or 0, depending whether the compiler supports simple visibility declarations.])
+])
diff --git a/test/.gitignore b/test/.gitignore
index 78dfbd30..4eaae4a4 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -29,8 +29,11 @@ test-relay
test-dbus-daemon
test-marshal
manual-authz
+manual-dir-iter
+manual-tcp
test-dbus-daemon-eavesdrop
test-printf
test-refs
test-syntax
test-syslog
+internals/.dirstamp
diff --git a/test/Makefile.am b/test/Makefile.am
index e0ed3c87..9540a2c1 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -4,59 +4,48 @@
SUBDIRS= . name-test
DIST_SUBDIRS=name-test
-# CPPFLAGS for binaries that are normally dynamic
+CLEANFILES =
+EXTRA_DIST =
+
AM_CPPFLAGS = \
-I$(top_srcdir) \
$(DBUS_STATIC_BUILD_CPPFLAGS) \
+ -DDBUS_COMPILATION \
$(GLIB_CFLAGS) \
- $(DBUS_GLIB_CFLAGS) \
$(NULL)
# improve backtraces from test stuff
AM_LDFLAGS = @R_DYNAMIC_LDFLAG@
-# CPPFLAGS for binaries that are always static
-static_cppflags = \
- $(AM_CPPFLAGS) \
- -DDBUS_STATIC_BUILD \
- -DDBUS_COMPILATION \
- -DDBUS_TEST_USE_INTERNAL \
- $(NULL)
-
-noinst_LTLIBRARIES = libdbus-testutils-internal.la
+noinst_LTLIBRARIES = libdbus-testutils.la
-# You can link either libdbus-testutils, dbus-glib and libdbus-1,
-# or libdbus-testutils-internal and libdbus-internal - never both in the
-# same binary.
-if DBUS_WITH_DBUS_GLIB
-noinst_LTLIBRARIES += libdbus-testutils.la
libdbus_testutils_la_SOURCES = \
test-utils.c \
test-utils.h \
$(NULL)
-libdbus_testutils_la_LIBADD = \
- $(top_builddir)/dbus/libdbus-1.la \
- $(GLIB_LIBS) \
- $(DBUS_GLIB_LIBS) \
+
+if DBUS_WITH_GLIB
+libdbus_testutils_la_SOURCES += \
+ test-utils-glib.c \
+ test-utils-glib.h \
$(NULL)
-testutils_shared_if_possible_cppflags = $(AM_CPPFLAGS)
-testutils_shared_if_possible_libs = libdbus-testutils.la
-else
-testutils_shared_if_possible_cppflags = $(static_cppflags)
-testutils_shared_if_possible_libs = libdbus-testutils-internal.la
endif
-libdbus_testutils_internal_la_CPPFLAGS = \
- $(static_cppflags) \
- $(NULL)
-libdbus_testutils_internal_la_SOURCES = \
- test-utils.c \
- test-utils.h \
- $(NULL)
-libdbus_testutils_internal_la_LIBADD = \
+libdbus_testutils_la_LIBADD = \
+ $(top_builddir)/dbus/libdbus-1.la \
$(top_builddir)/dbus/libdbus-internal.la \
$(NULL)
+TEST_EXTENSIONS = .sh
+
+LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/build-aux/tap-driver.sh
+LOG_COMPILER = $(srcdir)/glib-tap-test.sh
+SH_LOG_DRIVER = $(LOG_DRIVER)
+SH_LOG_COMPILER = $(SHELL)
+EXTRA_DIST += glib-tap-test.sh
+
+TESTS =
+
if DBUS_ENABLE_EMBEDDED_TESTS
## break-loader removed for now
## these binaries are used in tests but are not themselves tests
@@ -72,154 +61,202 @@ TEST_BINARIES = \
## These are conceptually part of directories that come earlier in SUBDIRS
## order, but we don't want to run them til we arrive in this directory,
-## since they depend on stuff from this directory
-TESTS = \
- ../bus/test-bus$(EXEEXT) \
- ../bus/test-bus-system$(EXEEXT) \
- ../dbus/test-dbus$(EXEEXT) \
- $(NULL)
+## since they depend on stuff from this directory. We wrap them in a
+## simple shell script to get TAP output.
+
+wrap_bus_tests = test-bus.sh
+wrap_dbus_tests = test-dbus.sh
if DBUS_UNIX
-TESTS += ../bus/test-bus-launch-helper$(EXEEXT)
+wrap_bus_tests += test-bus-launch-helper.sh
+wrap_bus_tests += test-bus-system.sh
endif
+TESTS += $(wrap_bus_tests) $(wrap_dbus_tests)
+CLEANFILES += $(wrap_bus_tests) $(wrap_dbus_tests)
+EXTRA_DIST += tap-test.sh.in
+
+$(wrap_bus_tests): test-bus%.sh: ../bus/test-bus%$(EXEEXT) tap-test.sh.in Makefile
+ sed -e 's![@]RUN[@]!$<!' \
+ < $(srcdir)/tap-test.sh.in > $@
+
+$(wrap_dbus_tests): test-dbus%.sh: ../dbus/test-dbus%$(EXEEXT) tap-test.sh.in Makefile
+ sed -e 's![@]RUN[@]!$<!' \
+ < $(srcdir)/tap-test.sh.in > $@
+
else !DBUS_ENABLE_EMBEDDED_TESTS
TEST_BINARIES=
-TESTS=
endif !DBUS_ENABLE_EMBEDDED_TESTS
noinst_PROGRAMS= $(TEST_BINARIES)
-test_service_CPPFLAGS = $(static_cppflags)
-test_service_LDADD = libdbus-testutils-internal.la
-test_names_CPPFLAGS = $(static_cppflags)
-test_names_LDADD = libdbus-testutils-internal.la
-## break_loader_CPPFLAGS = $(static_cppflags)
+test_service_LDADD = libdbus-testutils.la
+test_names_LDADD = libdbus-testutils.la
## break_loader_LDADD = $(top_builddir)/dbus/libdbus-internal.la
-test_shell_service_CPPFLAGS = $(static_cppflags)
-test_shell_service_LDADD = libdbus-testutils-internal.la
+test_shell_service_LDADD = libdbus-testutils.la
test_shell_SOURCES = shell-test.c
-test_shell_CPPFLAGS = $(static_cppflags)
-test_shell_LDADD = libdbus-testutils-internal.la
+test_shell_LDADD = libdbus-testutils.la
test_spawn_SOURCES = spawn-test.c
-test_spawn_CPPFLAGS = $(static_cppflags)
test_spawn_LDADD = $(top_builddir)/dbus/libdbus-internal.la
test_printf_SOURCES = internals/printf.c
-test_printf_CPPFLAGS = $(static_cppflags)
test_printf_LDADD = $(top_builddir)/dbus/libdbus-internal.la
test_refs_SOURCES = internals/refs.c
-test_refs_CPPFLAGS = $(static_cppflags)
-test_refs_LDADD = libdbus-testutils-internal.la $(GLIB_LIBS)
+test_refs_LDADD = libdbus-testutils.la $(GLIB_LIBS)
test_syslog_SOURCES = internals/syslog.c
-test_syslog_CPPFLAGS = $(static_cppflags)
-test_syslog_LDADD = libdbus-testutils-internal.la $(GLIB_LIBS)
+test_syslog_LDADD = libdbus-testutils.la $(GLIB_LIBS)
+
+manual_dir_iter_SOURCES = manual-dir-iter.c
+manual_dir_iter_LDADD = $(top_builddir)/dbus/libdbus-internal.la
+
+manual_paths_SOURCES = manual-paths.c
+manual_paths_LDADD = $(top_builddir)/dbus/libdbus-internal.la
manual_tcp_SOURCES = manual-tcp.c
-manual_tcp_CPPFLAGS = $(static_cppflags)
manual_tcp_LDADD = $(top_builddir)/dbus/libdbus-internal.la
-EXTRA_DIST = dbus-test-runner
+EXTRA_DIST += dbus-test-runner
-testexecdir = $(libdir)/dbus-1.0/test
+testexecdir = $(libexecdir)/installed-tests/dbus
+testmetadir = $(datadir)/installed-tests/dbus
testexec_PROGRAMS =
+testmeta_DATA =
installable_tests = \
test-shell \
test-printf \
$(NULL)
installable_manual_tests = \
- manual-tcp \
- $(NULL)
+ manual-dir-iter \
+ manual-tcp \
+ $(NULL)
+
+if DBUS_WIN
+installable_manual_tests += manual-paths
+endif
if DBUS_WITH_GLIB
installable_tests += \
test-corrupt \
test-dbus-daemon \
test-dbus-daemon-eavesdrop \
+ test-fdpass \
+ test-monitor \
test-loopback \
test-marshal \
test-refs \
test-relay \
+ test-sd-activation \
test-syntax \
test-syslog \
+ test-uid-permissions \
$(NULL)
installable_manual_tests += \
manual-authz \
$(NULL)
endif DBUS_WITH_GLIB
+installable_test_meta = $(installable_tests:=.test)
+installable_test_meta_with_config = $(installable_tests:=_with_config.test)
+
installcheck_tests =
installcheck_environment = \
- XDG_RUNTIME_DIR=@abs_top_builddir@/test/XDG_RUNTIME_DIR \
- DBUS_TEST_DAEMON=$(DESTDIR)$(DBUS_DAEMONDIR)/dbus-daemon$(EXEEXT) \
- DBUS_TEST_HOMEDIR=@abs_top_builddir@/dbus \
- DBUS_TEST_SYSCONFDIR=$(DESTDIR)$(sysconfdir)
-
-TESTS_ENVIRONMENT = \
- XDG_RUNTIME_DIR=@abs_top_builddir@/test/XDG_RUNTIME_DIR \
- DBUS_FATAL_WARNINGS=1 \
- DBUS_TEST_DAEMON=@abs_top_builddir@/bus/dbus-daemon$(EXEEXT) \
- DBUS_TEST_DATA=@abs_top_builddir@/test/data \
- DBUS_TEST_HOMEDIR=@abs_top_builddir@/dbus \
+ export XDG_RUNTIME_DIR=@abs_top_builddir@/test/XDG_RUNTIME_DIR; \
+ export DBUS_TEST_DAEMON=$(DESTDIR)$(DBUS_DAEMONDIR)/dbus-daemon$(EXEEXT); \
+ export DBUS_TEST_HOMEDIR=@abs_top_builddir@/dbus; \
+ export DBUS_TEST_DATADIR=$(DESTDIR)$(datadir); \
+ ${NULL}
+
+AM_TESTS_ENVIRONMENT = \
+ export XDG_RUNTIME_DIR=@abs_top_builddir@/test/XDG_RUNTIME_DIR; \
+ export DBUS_FATAL_WARNINGS=1; \
+ export DBUS_TEST_DAEMON=@abs_top_builddir@/bus/dbus-daemon$(EXEEXT); \
+ export DBUS_TEST_DATA=@abs_top_builddir@/test/data; \
+ export DBUS_TEST_HOMEDIR=@abs_top_builddir@/dbus; \
$(NULL)
manual_authz_SOURCES = manual-authz.c
-manual_authz_CPPFLAGS = $(testutils_shared_if_possible_cppflags)
manual_authz_LDADD = \
- $(testutils_shared_if_possible_libs) \
+ libdbus-testutils.la \
$(GLIB_LIBS) \
$(NULL)
test_corrupt_SOURCES = corrupt.c
-test_corrupt_CPPFLAGS = $(testutils_shared_if_possible_cppflags)
test_corrupt_LDADD = \
- $(testutils_shared_if_possible_libs) \
+ libdbus-testutils.la \
$(GLIB_LIBS) \
$(NULL)
test_loopback_SOURCES = loopback.c
-test_loopback_CPPFLAGS = $(testutils_shared_if_possible_cppflags)
test_loopback_LDADD = \
- $(testutils_shared_if_possible_libs) \
+ libdbus-testutils.la \
$(GLIB_LIBS) \
$(NULL)
test_relay_SOURCES = relay.c
-test_relay_CPPFLAGS = $(testutils_shared_if_possible_cppflags)
test_relay_LDADD = \
- $(testutils_shared_if_possible_libs) \
+ libdbus-testutils.la \
$(GLIB_LIBS) \
$(NULL)
test_dbus_daemon_SOURCES = dbus-daemon.c
-test_dbus_daemon_CPPFLAGS = $(testutils_shared_if_possible_cppflags)
test_dbus_daemon_LDADD = \
- $(testutils_shared_if_possible_libs) \
+ libdbus-testutils.la \
$(GLIB_LIBS) \
$(NULL)
test_dbus_daemon_eavesdrop_SOURCES = dbus-daemon-eavesdrop.c
-test_dbus_daemon_eavesdrop_CPPFLAGS = $(testutils_shared_if_possible_cppflags)
test_dbus_daemon_eavesdrop_LDADD = \
- $(testutils_shared_if_possible_libs) \
+ libdbus-testutils.la \
+ $(GLIB_LIBS) \
+ $(NULL)
+
+test_sd_activation_SOURCES = \
+ sd-activation.c \
+ $(NULL)
+test_sd_activation_LDADD = \
+ libdbus-testutils.la \
$(GLIB_LIBS) \
$(NULL)
test_marshal_SOURCES = marshal.c
test_marshal_LDADD = \
- $(top_builddir)/dbus/libdbus-1.la \
+ libdbus-testutils.la \
+ $(GLIB_LIBS) \
+ $(NULL)
+
+test_monitor_SOURCES = \
+ monitor.c \
+ $(NULL)
+test_monitor_LDADD = \
+ libdbus-testutils.la \
$(GLIB_LIBS) \
$(NULL)
test_syntax_SOURCES = syntax.c
test_syntax_LDADD = \
- $(top_builddir)/dbus/libdbus-1.la \
+ libdbus-testutils.la \
+ $(GLIB_LIBS) \
+ $(NULL)
+
+test_uid_permissions_SOURCES = \
+ uid-permissions.c \
+ $(NULL)
+test_uid_permissions_LDADD = \
+ libdbus-testutils.la \
+ $(GLIB_LIBS) \
+ $(NULL)
+
+test_fdpass_SOURCES = \
+ fdpass.c \
+ $(NULL)
+test_fdpass_LDADD = \
+ libdbus-testutils.la \
$(GLIB_LIBS) \
$(NULL)
@@ -229,6 +266,9 @@ installcheck_tests += $(installable_tests)
if DBUS_ENABLE_INSTALLED_TESTS
testexec_PROGRAMS += $(installable_tests) $(installable_manual_tests)
+
+ testmeta_DATA += $(installable_test_meta)
+ testmeta_DATA += $(installable_test_meta_with_config)
else !DBUS_ENABLE_INSTALLED_TESTS
noinst_PROGRAMS += $(installable_tests) $(installable_manual_tests)
endif !DBUS_ENABLE_INSTALLED_TESTS
@@ -240,13 +280,13 @@ endif DBUS_ENABLE_MODULAR_TESTS
# do a portable equivalent of setting LD_LIBRARY_PATH.
installcheck-local:
$(MAKE) check-TESTS TESTS='$$(installcheck_tests)' \
- TESTS_ENVIRONMENT='$$(installcheck_environment)'
+ AM_TESTS_ENVIRONMENT='$$(installcheck_environment)'
if DBUS_ENABLE_INSTALLED_TESTS
- test -n "$(DESTDIR)" || \
+ test -n "$(DESTDIR)" || { \
$(installcheck_environment) \
$(srcdir)/dbus-test-runner \
$(testexecdir) \
- $(testexec_PROGRAMS)
+ $(testexec_PROGRAMS) }
endif DBUS_ENABLE_INSTALLED_TESTS
in_data = \
@@ -254,7 +294,11 @@ in_data = \
data/valid-config-files-system/debug-allow-all-pass.conf.in \
data/valid-config-files/debug-allow-all-sha1.conf.in \
data/valid-config-files/debug-allow-all.conf.in \
+ data/valid-config-files/finite-timeout.conf.in \
+ data/valid-config-files/forbidding.conf.in \
data/valid-config-files/incoming-limit.conf.in \
+ data/valid-config-files/multi-user.conf.in \
+ data/valid-config-files/systemd-activation.conf.in \
data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service.in \
data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service.in \
data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service.in \
@@ -323,9 +367,14 @@ static_data = \
data/sha-1/bit-messages.sha1 \
data/sha-1/byte-hashes.sha1 \
data/sha-1/byte-messages.sha1 \
+ data/systemd-activation/com.example.SystemdActivatable1.service \
+ data/systemd-activation/com.example.SystemdActivatable2.service \
+ data/systemd-activation/com.example.SystemdActivatable3.service \
+ data/systemd-activation/org.freedesktop.systemd1.service \
data/valid-config-files/basic.conf \
data/valid-config-files/basic.d/basic.conf \
data/valid-config-files/entities.conf \
+ data/valid-config-files/listen-unix-runtime.conf \
data/valid-config-files/many-rules.conf \
data/valid-config-files/system.d/test.conf \
data/valid-messages/array-of-array-of-uint32.message \
@@ -349,25 +398,82 @@ EXTRA_DIST += $(static_data)
## copy tests to builddir so that generated tests and static tests
## are all in one place.
-all-local:
+all-local: copy-config-local uninstalled-config-local
+ @:
+
+copy-config-local:
$(AM_V_at)$(MKDIR_P) data/valid-config-files/session.d
- $(AM_V_at)set -e && \
+ $(AM_V_GEN)set -e; \
if test $(srcdir) = . || test $(srcdir) -ef .; then \
echo '-- No need to copy test data as srcdir = builddir'; \
else \
for F in $(static_data); do \
- $(MKDIR_P) $${F%/*}; \
- rm -f $$F; \
- cp $(srcdir)/$$F $$F; \
+ $(MKDIR_P) "$${F%/*}"; \
+ rm -f "$$F"; \
+ cp $(srcdir)/"$$F" "$$F"; \
done; \
fi
+uninstalled-config-local:
+ $(AM_V_GEN)set -e; \
+ for F in $(in_data); do \
+ $(MKDIR_P) "$${F%/*}"; \
+ sed \
+ -e 's,[@]DBUS_TEST_DATA[@],@abs_builddir@/data,' \
+ -e 's,[@]DBUS_TEST_EXEC[@],@abs_builddir@,' \
+ -e 's,[@]EXEEXT[@],$(EXEEXT),' \
+ -e 's,[@]TEST_LAUNCH_HELPER_BINARY[@],@abs_top_builddir@/bus/dbus-daemon-launch-helper-test$(EXEEXT),' \
+ -e 's,[@]TEST_LISTEN[@],$(TEST_LISTEN),' \
+ < $(srcdir)/"$$F" > "$${F%.in}"; \
+ done
+
+installable-config-local:
+if DBUS_ENABLE_INSTALLED_TESTS
+ $(AM_V_GEN)set -e; \
+ for F in $(in_data); do \
+ $(MKDIR_P) "installable/$${F%/*}"; \
+ sed \
+ -e 's,[@]DBUS_TEST_DATA[@],$(testexecdir)/data,' \
+ -e 's,[@]DBUS_TEST_EXEC[@],$(testexecdir),' \
+ -e 's,[@]EXEEXT[@],$(EXEEXT),' \
+ -e 's,[@]TEST_LAUNCH_HELPER_BINARY[@],/bin/false,' \
+ -e 's,[@]TEST_LISTEN[@],$(TEST_LISTEN),' \
+ < $(srcdir)/"$$F" > "installable/$${F%.in}"; \
+ done
+else
+ @:
+endif
+
+
+install-data-local: install-config-local
+ @:
+
+install-config-local: installable-config-local
+if DBUS_ENABLE_INSTALLED_TESTS
+ $(AM_V_GEN)set -e; \
+ for F in $(static_data); do \
+ install -d "$(DESTDIR)$(testexecdir)/$${F%/*}"; \
+ install -m644 "$(srcdir)/$$F" "$(DESTDIR)$(testexecdir)/$$F"; \
+ done; \
+ for F in $(in_data); do \
+ install -d "$(DESTDIR)$(testexecdir)/$${F%/*}"; \
+ install -m644 "installable/$${F%.in}" "$(DESTDIR)$(testexecdir)/$${F%.in}"; \
+ done
+ ln -nfs $(datadir)/dbus-1/session.conf $(DESTDIR)$(testexecdir)/data/valid-config-files/session.conf
+ ln -nfs $(datadir)/dbus-1/system.conf $(DESTDIR)$(testexecdir)/data/valid-config-files/system.conf
+else
+ @:
+endif
+
## this doesn't clean most copied test data files when srcdir=builddir
clean-local:
$(AM_V_at)if test $(srcdir) = . || test $(srcdir) -ef .; then \
echo '-- No need to clean test data as srcdir = builddir'; \
else \
rm -f $(static_data); \
+ for F in $(in_data); do \
+ rm -f "$${F%.in}"; \
+ done; \
fi
imported_data = \
@@ -376,8 +482,28 @@ imported_data = \
$(NULL)
noinst_DATA = $(imported_data)
-CLEANFILES = $(noinst_DATA) XDG_RUNTIME_DIR
+CLEANFILES += \
+ $(noinst_DATA) \
+ XDG_RUNTIME_DIR \
+ installable \
+ $(NULL)
$(imported_data): data/valid-config-files/%.conf: $(top_builddir)/bus/%.conf
$(AM_V_at)$(MKDIR_P) data/valid-config-files
$(AM_V_GEN)cp $< $@
+
+$(installable_test_meta): %.test: %$(EXEEXT) Makefile
+ $(AM_V_GEN) ( \
+ echo '[Test]'; \
+ echo 'Type=session'; \
+ echo 'Output=TAP'; \
+ echo 'Exec=env $(testexecdir)/$* --tap'; \
+ ) > $@.tmp && mv $@.tmp $@
+
+$(installable_test_meta_with_config): %_with_config.test: %$(EXEEXT) Makefile
+ $(AM_V_GEN) ( \
+ echo '[Test]'; \
+ echo 'Type=session'; \
+ echo 'Output=TAP'; \
+ echo 'Exec=env DBUS_TEST_DATA=$(testexecdir)/data $(testexecdir)/$* --tap'; \
+ ) > $@.tmp && mv $@.tmp $@
diff --git a/test/corrupt.c b/test/corrupt.c
index 1a7d4460..d106fcc5 100644
--- a/test/corrupt.c
+++ b/test/corrupt.c
@@ -31,7 +31,7 @@
#include <dbus/dbus.h>
-#include "test-utils.h"
+#include "test-utils-glib.h"
typedef struct {
DBusError e;
@@ -110,7 +110,7 @@ test_connect (Fixture *f,
while (f->server_conn == NULL)
{
- g_print (".");
+ test_progress ('.');
test_main_context_iterate (f->ctx, TRUE);
}
@@ -139,7 +139,7 @@ test_message (Fixture *f,
while (g_queue_is_empty (&f->client_messages))
{
- g_print (".");
+ test_progress ('.');
test_main_context_iterate (f->ctx, TRUE);
}
@@ -231,7 +231,7 @@ test_corrupt (Fixture *f,
* rubbish, so it should disconnect */
while (g_queue_is_empty (&f->client_messages))
{
- g_print (".");
+ test_progress ('.');
test_main_context_iterate (f->ctx, TRUE);
}
@@ -320,7 +320,7 @@ test_byte_order (Fixture *f,
* message, so it should disconnect */
while (g_queue_is_empty (&f->client_messages))
{
- g_print (".");
+ test_progress ('.');
test_main_context_iterate (f->ctx, TRUE);
}
@@ -379,8 +379,7 @@ int
main (int argc,
char **argv)
{
- g_test_init (&argc, &argv, NULL);
- g_type_init ();
+ test_init (&argc, &argv);
g_test_add ("/corrupt/tcp", Fixture, "tcp:host=127.0.0.1", setup,
test_corrupt, teardown);
diff --git a/test/data/systemd-activation/com.example.SystemdActivatable1.service b/test/data/systemd-activation/com.example.SystemdActivatable1.service
new file mode 100644
index 00000000..f15f0386
--- /dev/null
+++ b/test/data/systemd-activation/com.example.SystemdActivatable1.service
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name=com.example.SystemdActivatable1
+Exec=/bin/false 1
+SystemdService=dbus-com.example.SystemdActivatable1.service
diff --git a/test/data/systemd-activation/com.example.SystemdActivatable2.service b/test/data/systemd-activation/com.example.SystemdActivatable2.service
new file mode 100644
index 00000000..dcedd734
--- /dev/null
+++ b/test/data/systemd-activation/com.example.SystemdActivatable2.service
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name=com.example.SystemdActivatable2
+Exec=/bin/false 2
+SystemdService=dbus-com.example.SystemdActivatable2.service
diff --git a/test/data/systemd-activation/com.example.SystemdActivatable3.service b/test/data/systemd-activation/com.example.SystemdActivatable3.service
new file mode 100644
index 00000000..f6f0559c
--- /dev/null
+++ b/test/data/systemd-activation/com.example.SystemdActivatable3.service
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name=com.example.SystemdActivatable3
+Exec=/bin/false 3
+SystemdService=dbus-com.example.SystemdActivatable3.service
diff --git a/test/data/systemd-activation/org.freedesktop.systemd1.service b/test/data/systemd-activation/org.freedesktop.systemd1.service
new file mode 100644
index 00000000..aea93113
--- /dev/null
+++ b/test/data/systemd-activation/org.freedesktop.systemd1.service
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.freedesktop.systemd1
+Exec=/bin/false
diff --git a/test/data/valid-config-files/.gitignore b/test/data/valid-config-files/.gitignore
index a38e9d15..2a09552e 100644
--- a/test/data/valid-config-files/.gitignore
+++ b/test/data/valid-config-files/.gitignore
@@ -1,5 +1,7 @@
debug-allow-all.conf
debug-allow-all-sha1.conf
+incoming-limit.conf
session.conf
system.conf
run-with-tmp-session-bus.conf
+finite-timeout.conf
diff --git a/test/data/valid-config-files/finite-timeout.conf.in b/test/data/valid-config-files/finite-timeout.conf.in
new file mode 100644
index 00000000..7d26d715
--- /dev/null
+++ b/test/data/valid-config-files/finite-timeout.conf.in
@@ -0,0 +1,19 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <!-- Our well-known bus type, don't change this -->
+ <type>session</type>
+ <listen>@TEST_LISTEN@</listen>
+
+ <policy context="default">
+ <!-- Allow everything to be sent -->
+ <allow send_destination="*" eavesdrop="true"/>
+ <!-- Allow everything to be received -->
+ <allow eavesdrop="true"/>
+ <!-- Allow anyone to own anything -->
+ <allow own="*"/>
+ </policy>
+
+ <!-- Forcibly time out method calls after 100ms -->
+ <limit name="reply_timeout">100</limit>
+</busconfig>
diff --git a/test/data/valid-config-files/forbidding.conf.in b/test/data/valid-config-files/forbidding.conf.in
new file mode 100644
index 00000000..6a674f88
--- /dev/null
+++ b/test/data/valid-config-files/forbidding.conf.in
@@ -0,0 +1,18 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <!-- Our well-known bus type, don't change this -->
+ <type>session</type>
+ <listen>@TEST_LISTEN@</listen>
+
+ <policy context="default">
+ <!-- Allow everything -->
+ <allow send_destination="*"/>
+ <allow receive_sender="*"/>
+ <allow own="*"/>
+
+ <!-- Exception: some messages are forbidden -->
+ <deny send_interface="com.example.CannotSend"/>
+ <deny receive_interface="com.example.CannotReceive"/>
+ </policy>
+</busconfig>
diff --git a/test/data/valid-config-files/listen-unix-runtime.conf b/test/data/valid-config-files/listen-unix-runtime.conf
new file mode 100644
index 00000000..169de2cb
--- /dev/null
+++ b/test/data/valid-config-files/listen-unix-runtime.conf
@@ -0,0 +1,11 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <type>session</type>
+ <listen>unix:runtime=yes</listen>
+ <policy context="default">
+ <allow send_destination="*" eavesdrop="true"/>
+ <allow eavesdrop="true"/>
+ <allow own="*"/>
+ </policy>
+</busconfig>
diff --git a/test/data/valid-config-files/multi-user.conf.in b/test/data/valid-config-files/multi-user.conf.in
new file mode 100644
index 00000000..37a7da67
--- /dev/null
+++ b/test/data/valid-config-files/multi-user.conf.in
@@ -0,0 +1,15 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <listen>@TEST_LISTEN@</listen>
+
+ <policy context="default">
+ <allow send_interface="*"/>
+ <allow receive_interface="*"/>
+ <allow own="*"/>
+ <allow user="*"/>
+ </policy>
+
+ <!-- avoid allowing service activation since we are allowing everyone in -->
+ <servicehelper>/bin/false</servicehelper>
+</busconfig>
diff --git a/test/data/valid-config-files/systemd-activation.conf.in b/test/data/valid-config-files/systemd-activation.conf.in
new file mode 100644
index 00000000..bcd6416c
--- /dev/null
+++ b/test/data/valid-config-files/systemd-activation.conf.in
@@ -0,0 +1,11 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <listen>@TEST_LISTEN@</listen>
+ <servicedir>@DBUS_TEST_DATA@/systemd-activation</servicedir>
+ <policy context="default">
+ <allow send_destination="*"/>
+ <allow receive_sender="*"/>
+ <allow own="*"/>
+ </policy>
+</busconfig>
diff --git a/test/dbus-daemon-eavesdrop.c b/test/dbus-daemon-eavesdrop.c
index a78d8888..41985787 100644
--- a/test/dbus-daemon-eavesdrop.c
+++ b/test/dbus-daemon-eavesdrop.c
@@ -27,21 +27,9 @@
#include <config.h>
-#include <glib.h>
-
-#include <dbus/dbus.h>
-
#include <string.h>
-#ifdef DBUS_WIN
-# include <io.h>
-# include <windows.h>
-#else
-# include <signal.h>
-# include <unistd.h>
-#endif
-
-#include "test-utils.h"
+#include "test-utils-glib.h"
#define SENDER_NAME "test.eavesdrop.sender"
#define SENDER_PATH "/test/eavesdrop/sender"
@@ -91,99 +79,6 @@ typedef struct {
dbus_bool_t politelistener_got_stopper;
} Fixture;
-#define assert_no_error(e) _assert_no_error (e, __FILE__, __LINE__)
-static void
-_assert_no_error (const DBusError *e,
- const char *file,
- int line)
-{
- if (G_UNLIKELY (dbus_error_is_set (e)))
- g_error ("%s:%d: expected success but got error: %s: %s",
- file, line, e->name, e->message);
-}
-
-static gchar *
-spawn_dbus_daemon (gchar *binary,
- gchar *configuration,
- GPid *daemon_pid)
-{
- GError *error = NULL;
- GString *address;
- gint address_fd;
- gchar *argv[] = {
- binary,
- configuration,
- "--nofork",
- "--print-address=1", /* stdout */
- NULL
- };
-
- g_spawn_async_with_pipes (NULL, /* working directory */
- argv,
- NULL, /* envp */
- G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
- NULL, /* child_setup */
- NULL, /* user data */
- daemon_pid,
- NULL, /* child's stdin = /dev/null */
- &address_fd,
- NULL, /* child's stderr = our stderr */
- &error);
- g_assert_no_error (error);
-
- address = g_string_new (NULL);
-
- /* polling until the dbus-daemon writes out its address is a bit stupid,
- * but at least it's simple, unlike dbus-launch... in principle we could
- * use select() here, but life's too short */
- while (1)
- {
- gssize bytes;
- gchar buf[4096];
- gchar *newline;
-
- bytes = read (address_fd, buf, sizeof (buf));
-
- if (bytes > 0)
- g_string_append_len (address, buf, bytes);
-
- newline = strchr (address->str, '\n');
-
- if (newline != NULL)
- {
- if ((newline > address->str) && ('\r' == newline[-1]))
- newline -= 1;
- g_string_truncate (address, newline - address->str);
- break;
- }
-
- g_usleep (G_USEC_PER_SEC / 10);
- }
-
- return g_string_free (address, FALSE);
-}
-
-static DBusConnection *
-connect_to_bus (Fixture *f,
- const gchar *address)
-{
- DBusConnection *conn;
- DBusError error = DBUS_ERROR_INIT;
- dbus_bool_t ok;
-
- conn = dbus_connection_open_private (address, &error);
- assert_no_error (&error);
- g_assert (conn != NULL);
-
- ok = dbus_bus_register (conn, &error);
- assert_no_error (&error);
- g_assert (ok);
- g_assert (dbus_bus_get_unique_name (conn) != NULL);
-
- test_connection_setup (f->ctx, conn);
- return conn;
-}
-
/* send a unicast signal to <self> to ensure that no other connection
* listening is the actual recipient for the signal */
static DBusHandlerResult
@@ -338,9 +233,9 @@ add_receiver_filter (Fixture *f)
DBusError e = DBUS_ERROR_INIT;
dbus_bus_add_match (f->receiver, RECEIVER_RULE, &e);
- assert_no_error (&e);
+ test_assert_no_error (&e);
dbus_bus_add_match (f->receiver, STOPPER_RULE, &e);
- assert_no_error (&e);
+ test_assert_no_error (&e);
if (!dbus_connection_add_filter (f->receiver,
signal_filter, f, NULL))
@@ -353,9 +248,9 @@ add_eavesdropper_filter (Fixture *f)
DBusError e = DBUS_ERROR_INIT;
dbus_bus_add_match (f->eavesdropper, EAVESDROPPER_RULE, &e);
- assert_no_error (&e);
+ test_assert_no_error (&e);
dbus_bus_add_match (f->eavesdropper, STOPPER_RULE, &e);
- assert_no_error (&e);
+ test_assert_no_error (&e);
if (!dbus_connection_add_filter (f->eavesdropper,
signal_filter, f, NULL))
@@ -368,9 +263,9 @@ add_politelistener_filter (Fixture *f)
DBusError e = DBUS_ERROR_INIT;
dbus_bus_add_match (f->politelistener, POLITELISTENER_RULE, &e);
- assert_no_error (&e);
+ test_assert_no_error (&e);
dbus_bus_add_match (f->politelistener, STOPPER_RULE, &e);
- assert_no_error (&e);
+ test_assert_no_error (&e);
if (!dbus_connection_add_filter (f->politelistener,
signal_filter, f, NULL))
@@ -381,8 +276,6 @@ static void
setup (Fixture *f,
gconstpointer context G_GNUC_UNUSED)
{
- gchar *dbus_daemon;
- gchar *config;
gchar *address;
f->ctx = test_main_context_get ();
@@ -390,45 +283,14 @@ setup (Fixture *f,
f->ge = NULL;
dbus_error_init (&f->e);
- dbus_daemon = g_strdup (g_getenv ("DBUS_TEST_DAEMON"));
-
- if (dbus_daemon == NULL)
- dbus_daemon = g_strdup ("dbus-daemon");
-
- if (g_getenv ("DBUS_TEST_SYSCONFDIR") != NULL)
- {
- config = g_strdup_printf ("--config-file=%s/dbus-1/session.conf",
- g_getenv ("DBUS_TEST_SYSCONFDIR"));
- }
- else if (g_getenv ("DBUS_TEST_DATA") != NULL)
- {
- config = g_strdup_printf (
- "--config-file=%s/valid-config-files/session.conf",
- g_getenv ("DBUS_TEST_DATA"));
- }
- else
- {
- config = g_strdup ("--session");
- }
-
- if (g_getenv ("DBUS_TEST_DAEMON_ADDRESS") != NULL)
- {
- address = g_strdup (g_getenv ("DBUS_TEST_DAEMON_ADDRESS"));
- }
- else
- {
- address = spawn_dbus_daemon (dbus_daemon, config, &f->daemon_pid);
- }
-
- g_free (dbus_daemon);
- g_free (config);
+ address = test_get_dbus_daemon (NULL, TEST_USER_ME, &f->daemon_pid);
- f->sender = connect_to_bus (f, address);
+ f->sender = test_connect_to_bus (f->ctx, address);
dbus_bus_request_name (f->sender, SENDER_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE,
&(f->e));
- f->receiver = connect_to_bus (f, address);
- f->eavesdropper = connect_to_bus (f, address);
- f->politelistener = connect_to_bus (f, address);
+ f->receiver = test_connect_to_bus (f->ctx, address);
+ f->eavesdropper = test_connect_to_bus (f->ctx, address);
+ f->politelistener = test_connect_to_bus (f->ctx, address);
add_receiver_filter (f);
add_politelistener_filter (f);
add_eavesdropper_filter (f);
@@ -541,12 +403,7 @@ teardown (Fixture *f,
f->eavesdropper = NULL;
}
-#ifdef DBUS_WIN
- TerminateProcess (f->daemon_pid, 1);
-#else
- kill (f->daemon_pid, SIGTERM);
-#endif
-
+ test_kill_pid (f->daemon_pid);
g_spawn_close_pid (f->daemon_pid);
test_main_context_unref (f->ctx);
@@ -556,8 +413,7 @@ int
main (int argc,
char **argv)
{
- g_test_init (&argc, &argv, NULL);
- g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id=");
+ test_init (&argc, &argv);
g_test_add ("/eavedrop/match_keyword/broadcast", Fixture, NULL,
setup, test_eavesdrop_broadcast, teardown);
diff --git a/test/dbus-daemon.c b/test/dbus-daemon.c
index dc0f1317..72bcd08c 100644
--- a/test/dbus-daemon.c
+++ b/test/dbus-daemon.c
@@ -2,6 +2,7 @@
*
* Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
* Copyright © 2010-2011 Nokia Corporation
+ * Copyright © 2015 Collabora Ltd.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
@@ -26,22 +27,47 @@
#include <config.h>
-#include <glib.h>
+#include <errno.h>
+#include <string.h>
#include <dbus/dbus.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include "test-utils-glib.h"
+
#include <string.h>
-#ifdef DBUS_WIN
-# include <io.h>
-# include <windows.h>
-#else
-# include <signal.h>
+#ifdef DBUS_UNIX
# include <unistd.h>
# include <sys/types.h>
#endif
-#include "test-utils.h"
+/* Platforms where we know that credentials-passing passes both the
+ * uid and the pid. Please keep these in alphabetical order.
+ *
+ * These platforms should #error in _dbus_read_credentials_socket()
+ * if we didn't detect their flavour of credentials-passing, since that
+ * would be a regression.
+ */
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
+ defined(__linux__) || \
+ defined(__NetBSD__) || \
+ defined(__OpenBSD__)
+# define UNIX_USER_SHOULD_WORK
+# define PID_SHOULD_WORK
+#endif
+
+/* Platforms where we know that credentials-passing passes the
+ * uid, but not necessarily the pid. Again, alphabetical order please.
+ *
+ * These platforms should also #error in _dbus_read_credentials_socket()
+ * if we didn't detect their flavour of credentials-passing.
+ */
+#if 0 /* defined(__your_platform_here__) */
+# define UNIX_USER_SHOULD_WORK
+#endif
typedef struct {
gboolean skip;
@@ -57,111 +83,30 @@ typedef struct {
DBusConnection *right_conn;
gboolean right_conn_echo;
-} Fixture;
-
-#define assert_no_error(e) _assert_no_error (e, __FILE__, __LINE__)
-static void
-_assert_no_error (const DBusError *e,
- const char *file,
- int line)
-{
- if (G_UNLIKELY (dbus_error_is_set (e)))
- g_error ("%s:%d: expected success but got error: %s: %s",
- file, line, e->name, e->message);
-}
-
-static gchar *
-spawn_dbus_daemon (gchar *binary,
- gchar *configuration,
- GPid *daemon_pid)
-{
- GError *error = NULL;
- GString *address;
- gint address_fd;
- gchar *argv[] = {
- binary,
- configuration,
- "--nofork",
- "--print-address=1", /* stdout */
- NULL
- };
-
- g_spawn_async_with_pipes (NULL, /* working directory */
- argv,
- NULL, /* envp */
- G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
- NULL, /* child_setup */
- NULL, /* user data */
- daemon_pid,
- NULL, /* child's stdin = /dev/null */
- &address_fd,
- NULL, /* child's stderr = our stderr */
- &error);
- g_assert_no_error (error);
-
- address = g_string_new (NULL);
-
- /* polling until the dbus-daemon writes out its address is a bit stupid,
- * but at least it's simple, unlike dbus-launch... in principle we could
- * use select() here, but life's too short */
- while (1)
- {
- gssize bytes;
- gchar buf[4096];
- gchar *newline;
-
- bytes = read (address_fd, buf, sizeof (buf));
+ gboolean wait_forever_called;
- if (bytes > 0)
- g_string_append_len (address, buf, bytes);
-
- newline = strchr (address->str, '\n');
-
- if (newline != NULL)
- {
- if ((newline > address->str) && ('\r' == newline[-1]))
- newline -= 1;
- g_string_truncate (address, newline - address->str);
- break;
- }
-
- g_usleep (G_USEC_PER_SEC / 10);
- }
-
- return g_string_free (address, FALSE);
-}
-
-static DBusConnection *
-connect_to_bus (Fixture *f,
- const gchar *address)
-{
- DBusConnection *conn;
- DBusError error = DBUS_ERROR_INIT;
- dbus_bool_t ok;
-
- conn = dbus_connection_open_private (address, &error);
- assert_no_error (&error);
- g_assert (conn != NULL);
-
- ok = dbus_bus_register (conn, &error);
- assert_no_error (&error);
- g_assert (ok);
- g_assert (dbus_bus_get_unique_name (conn) != NULL);
-
- test_connection_setup (f->ctx, conn);
- return conn;
-}
+ gchar *tmp_runtime_dir;
+ gchar *saved_runtime_dir;
+} Fixture;
static DBusHandlerResult
echo_filter (DBusConnection *connection,
DBusMessage *message,
void *user_data)
{
+ Fixture *f = user_data;
DBusMessage *reply;
if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ /* WaitForever() never replies, emulating a service that has got stuck */
+ if (dbus_message_is_method_call (message, "com.example", "WaitForever"))
+ {
+ f->wait_forever_called = TRUE;
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
reply = dbus_message_new_method_return (message);
if (reply == NULL)
@@ -179,6 +124,7 @@ typedef struct {
const char *bug_ref;
guint min_messages;
const char *config_file;
+ enum { SPECIFY_ADDRESS = 0, RELY_ON_DEFAULT } connect_mode;
} Config;
static void
@@ -186,78 +132,57 @@ setup (Fixture *f,
gconstpointer context)
{
const Config *config = context;
- gchar *dbus_daemon;
- gchar *arg;
gchar *address;
f->ctx = test_main_context_get ();
f->ge = NULL;
dbus_error_init (&f->e);
- if (config != NULL && config->config_file != NULL)
+ if (config != NULL && config->connect_mode == RELY_ON_DEFAULT)
{
- if (g_getenv ("DBUS_TEST_DAEMON_ADDRESS") != NULL)
- {
- g_message ("SKIP: cannot use DBUS_TEST_DAEMON_ADDRESS for "
- "unusally-configured dbus-daemon");
- f->skip = TRUE;
- return;
- }
-
- if (g_getenv ("DBUS_TEST_DATA") == NULL)
- {
- g_message ("SKIP: set DBUS_TEST_DATA to a directory containing %s",
- config->config_file);
- f->skip = TRUE;
- return;
- }
+ /* this is chosen to be something needing escaping */
+ f->tmp_runtime_dir = g_dir_make_tmp ("dbus=daemon=test.XXXXXX", &f->ge);
+ g_assert_no_error (f->ge);
- arg = g_strdup_printf (
- "--config-file=%s/%s",
- g_getenv ("DBUS_TEST_DATA"), config->config_file);
- }
- else if (g_getenv ("DBUS_TEST_SYSCONFDIR") != NULL)
- {
- arg = g_strdup_printf ("--config-file=%s/dbus-1/session.conf",
- g_getenv ("DBUS_TEST_SYSCONFDIR"));
+ /* we're relying on being single-threaded for this to be safe */
+ f->saved_runtime_dir = g_strdup (g_getenv ("XDG_RUNTIME_DIR"));
+ g_setenv ("XDG_RUNTIME_DIR", f->tmp_runtime_dir, TRUE);
}
- else if (g_getenv ("DBUS_TEST_DATA") != NULL)
- {
- arg = g_strdup_printf (
- "--config-file=%s/valid-config-files/session.conf",
- g_getenv ("DBUS_TEST_DATA"));
- }
- else
+
+ address = test_get_dbus_daemon (config ? config->config_file : NULL,
+ TEST_USER_ME,
+ &f->daemon_pid);
+
+ if (address == NULL)
{
- arg = g_strdup ("--session");
+ f->skip = TRUE;
+ return;
}
- dbus_daemon = g_strdup (g_getenv ("DBUS_TEST_DAEMON"));
+ f->left_conn = test_connect_to_bus (f->ctx, address);
- if (dbus_daemon == NULL)
- dbus_daemon = g_strdup ("dbus-daemon");
-
- if (g_getenv ("DBUS_TEST_DAEMON_ADDRESS") != NULL)
+ if (config != NULL && config->connect_mode == RELY_ON_DEFAULT)
{
- address = g_strdup (g_getenv ("DBUS_TEST_DAEMON_ADDRESS"));
+ /* use the default bus for the echo service ("right"), to check that
+ * it ends up on the same bus as the client ("left") */
+ f->right_conn = dbus_bus_get_private (DBUS_BUS_SESSION, &f->e);
+ test_assert_no_error (&f->e);
+
+ if (!test_connection_setup (f->ctx, f->right_conn))
+ g_error ("OOM");
}
else
{
- address = spawn_dbus_daemon (dbus_daemon, arg, &f->daemon_pid);
+ f->right_conn = test_connect_to_bus (f->ctx, address);
}
- g_free (dbus_daemon);
- g_free (arg);
-
- f->left_conn = connect_to_bus (f, address);
- f->right_conn = connect_to_bus (f, address);
g_free (address);
}
static void
add_echo_filter (Fixture *f)
{
- if (!dbus_connection_add_filter (f->right_conn, echo_filter, NULL, NULL))
+ if (!dbus_connection_add_filter (f->right_conn, echo_filter, f, NULL))
g_error ("OOM");
f->right_conn_echo = TRUE;
@@ -333,13 +258,77 @@ test_echo (Fixture *f,
}
static void
-pending_call_store_reply (DBusPendingCall *pc,
- void *data)
+test_no_reply (Fixture *f,
+ gconstpointer context)
{
- DBusMessage **message_p = data;
+ const Config *config = context;
+ DBusMessage *m;
+ DBusPendingCall *pc;
+ DBusMessage *reply = NULL;
+ enum { TIMEOUT, DISCONNECT } mode;
+ gboolean ok;
+
+ if (f->skip)
+ return;
+
+ g_test_bug ("76112");
+
+ if (config != NULL && config->config_file != NULL)
+ mode = TIMEOUT;
+ else
+ mode = DISCONNECT;
+
+ m = dbus_message_new_method_call (
+ dbus_bus_get_unique_name (f->right_conn), "/",
+ "com.example", "WaitForever");
+
+ add_echo_filter (f);
+
+ if (m == NULL)
+ g_error ("OOM");
+
+ if (!dbus_connection_send_with_reply (f->left_conn, m, &pc,
+ DBUS_TIMEOUT_INFINITE) ||
+ pc == NULL)
+ g_error ("OOM");
+
+ if (dbus_pending_call_get_completed (pc))
+ test_pending_call_store_reply (pc, &reply);
+ else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply,
+ &reply, NULL))
+ g_error ("OOM");
+
+ dbus_pending_call_unref (pc);
+ dbus_message_unref (m);
+
+ if (mode == DISCONNECT)
+ {
+ while (!f->wait_forever_called)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ dbus_connection_remove_filter (f->right_conn, echo_filter, f);
+ dbus_connection_close (f->right_conn);
+ dbus_connection_unref (f->right_conn);
+ f->right_conn = NULL;
+ }
+
+ while (reply == NULL)
+ test_main_context_iterate (f->ctx, TRUE);
- *message_p = dbus_pending_call_steal_reply (pc);
- g_assert (*message_p != NULL);
+ /* using inefficient string comparison for better assertion message */
+ g_assert_cmpstr (
+ dbus_message_type_to_string (dbus_message_get_type (reply)), ==,
+ dbus_message_type_to_string (DBUS_MESSAGE_TYPE_ERROR));
+ ok = dbus_set_error_from_message (&f->e, reply);
+ g_assert (ok);
+ g_assert_cmpstr (f->e.name, ==, DBUS_ERROR_NO_REPLY);
+
+ if (mode == DISCONNECT)
+ g_assert_cmpstr (f->e.message, ==,
+ "Message recipient disconnected from message bus without replying");
+ else
+ g_assert_cmpstr (f->e.message, ==,
+ "Message did not receive a reply (timeout by message bus)");
}
static void
@@ -357,7 +346,8 @@ test_creds (Fixture *f,
enum {
SEEN_UNIX_USER = 1,
SEEN_PID = 2,
- SEEN_WINDOWS_SID = 4
+ SEEN_WINDOWS_SID = 4,
+ SEEN_LINUX_SECURITY_LABEL = 8
} seen = 0;
if (m == NULL)
@@ -377,8 +367,8 @@ test_creds (Fixture *f,
m = NULL;
if (dbus_pending_call_get_completed (pc))
- pending_call_store_reply (pc, &m);
- else if (!dbus_pending_call_set_notify (pc, pending_call_store_reply,
+ test_pending_call_store_reply (pc, &m);
+ else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply,
&m, NULL))
g_error ("OOM");
@@ -416,13 +406,34 @@ test_creds (Fixture *f,
g_assert_cmpuint (dbus_message_iter_get_arg_type (&var_iter), ==,
DBUS_TYPE_UINT32);
dbus_message_iter_get_basic (&var_iter, &u32);
- g_message ("%s of this process is %u", name, u32);
+ g_test_message ("%s of this process is %u", name, u32);
g_assert_cmpuint (u32, ==, geteuid ());
seen |= SEEN_UNIX_USER;
#else
g_assert_not_reached ();
#endif
}
+ else if (g_strcmp0 (name, "WindowsSID") == 0)
+ {
+#ifdef G_OS_WIN32
+ gchar *sid;
+ char *self_sid;
+
+ g_assert (!(seen & SEEN_WINDOWS_SID));
+ g_assert_cmpuint (dbus_message_iter_get_arg_type (&var_iter), ==,
+ DBUS_TYPE_STRING);
+ dbus_message_iter_get_basic (&var_iter, &sid);
+ g_test_message ("%s of this process is %s", name, sid);
+ if (_dbus_getsid (&self_sid, 0))
+ {
+ g_assert_cmpstr (self_sid, ==, sid);
+ LocalFree(self_sid);
+ }
+ seen |= SEEN_WINDOWS_SID;
+#else
+ g_assert_not_reached ();
+#endif
+ }
else if (g_strcmp0 (name, "ProcessID") == 0)
{
guint32 u32;
@@ -431,7 +442,7 @@ test_creds (Fixture *f,
g_assert_cmpuint (dbus_message_iter_get_arg_type (&var_iter), ==,
DBUS_TYPE_UINT32);
dbus_message_iter_get_basic (&var_iter, &u32);
- g_message ("%s of this process is %u", name, u32);
+ g_test_message ("%s of this process is %u", name, u32);
#ifdef G_OS_UNIX
g_assert_cmpuint (u32, ==, getpid ());
#elif defined(G_OS_WIN32)
@@ -441,23 +452,111 @@ test_creds (Fixture *f,
#endif
seen |= SEEN_PID;
}
+ else if (g_strcmp0 (name, "LinuxSecurityLabel") == 0)
+ {
+#ifdef __linux__
+ gchar *label;
+ int len;
+ DBusMessageIter ay_iter;
+
+ g_assert (!(seen & SEEN_LINUX_SECURITY_LABEL));
+ g_assert_cmpuint (dbus_message_iter_get_arg_type (&var_iter), ==,
+ DBUS_TYPE_ARRAY);
+ dbus_message_iter_recurse (&var_iter, &ay_iter);
+ g_assert_cmpuint (dbus_message_iter_get_arg_type (&ay_iter), ==,
+ DBUS_TYPE_BYTE);
+ dbus_message_iter_get_fixed_array (&ay_iter, &label, &len);
+ g_test_message ("%s of this process is %s", name, label);
+ g_assert_cmpuint (strlen (label) + 1, ==, len);
+ seen |= SEEN_LINUX_SECURITY_LABEL;
+#else
+ g_assert_not_reached ();
+#endif
+ }
dbus_message_iter_next (&arr_iter);
}
-#ifdef G_OS_UNIX
+#ifdef UNIX_USER_SHOULD_WORK
g_assert (seen & SEEN_UNIX_USER);
+#endif
+
+#ifdef PID_SHOULD_WORK
g_assert (seen & SEEN_PID);
#endif
#ifdef G_OS_WIN32
- /* FIXME: when implemented:
g_assert (seen & SEEN_WINDOWS_SID);
- */
#endif
}
static void
+test_processid (Fixture *f,
+ gconstpointer context)
+{
+ const char *unique = dbus_bus_get_unique_name (f->left_conn);
+ DBusMessage *m = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetConnectionUnixProcessID");
+ DBusPendingCall *pc;
+ DBusError error = DBUS_ERROR_INIT;
+ guint32 pid;
+
+ if (m == NULL)
+ g_error ("OOM");
+
+ if (!dbus_message_append_args (m,
+ DBUS_TYPE_STRING, &unique,
+ DBUS_TYPE_INVALID))
+ g_error ("OOM");
+
+ if (!dbus_connection_send_with_reply (f->left_conn, m, &pc,
+ DBUS_TIMEOUT_USE_DEFAULT) ||
+ pc == NULL)
+ g_error ("OOM");
+
+ dbus_message_unref (m);
+ m = NULL;
+
+ if (dbus_pending_call_get_completed (pc))
+ test_pending_call_store_reply (pc, &m);
+ else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply,
+ &m, NULL))
+ g_error ("OOM");
+
+ while (m == NULL)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ if (dbus_message_get_args (m, &error,
+ DBUS_TYPE_UINT32, &pid,
+ DBUS_TYPE_INVALID))
+ {
+ g_assert_cmpstr (dbus_message_get_signature (m), ==, "u");
+ test_assert_no_error (&error);
+
+ g_test_message ("GetConnectionUnixProcessID returned %u", pid);
+
+#ifdef G_OS_UNIX
+ g_assert_cmpuint (pid, ==, getpid ());
+#elif defined(G_OS_WIN32)
+ g_assert_cmpuint (pid, ==, GetCurrentProcessId ());
+#else
+ g_assert_not_reached ();
+#endif
+ }
+ else
+ {
+ g_assert_cmpstr (error.name, ==, DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN);
+
+#ifdef PID_SHOULD_WORK
+ g_error ("Expected pid to be passed, but got %s: %s",
+ error.name, error.message);
+#endif
+
+ dbus_error_free (&error);
+ }
+}
+
+static void
test_canonical_path_uae (Fixture *f,
gconstpointer context)
{
@@ -487,8 +586,8 @@ test_canonical_path_uae (Fixture *f,
m = NULL;
if (dbus_pending_call_get_completed (pc))
- pending_call_store_reply (pc, &m);
- else if (!dbus_pending_call_set_notify (pc, pending_call_store_reply,
+ test_pending_call_store_reply (pc, &m);
+ else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply,
&m, NULL))
g_error ("OOM");
@@ -525,8 +624,8 @@ test_canonical_path_uae (Fixture *f,
m = NULL;
if (dbus_pending_call_get_completed (pc))
- pending_call_store_reply (pc, &m);
- else if (!dbus_pending_call_set_notify (pc, pending_call_store_reply,
+ test_pending_call_store_reply (pc, &m);
+ else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply,
&m, NULL))
g_error ("OOM");
@@ -560,7 +659,7 @@ teardown (Fixture *f,
{
if (f->right_conn_echo)
{
- dbus_connection_remove_filter (f->right_conn, echo_filter, NULL);
+ dbus_connection_remove_filter (f->right_conn, echo_filter, f);
f->right_conn_echo = FALSE;
}
@@ -571,36 +670,75 @@ teardown (Fixture *f,
if (f->daemon_pid != 0)
{
-#ifdef DBUS_WIN
- TerminateProcess (f->daemon_pid, 1);
-#else
- kill (f->daemon_pid, SIGTERM);
-#endif
-
+ test_kill_pid (f->daemon_pid);
g_spawn_close_pid (f->daemon_pid);
f->daemon_pid = 0;
}
+ if (f->tmp_runtime_dir != NULL)
+ {
+ gchar *path;
+
+ /* the socket may exist */
+ path = g_strdup_printf ("%s/bus", f->tmp_runtime_dir);
+ g_assert (g_remove (path) == 0 || errno == ENOENT);
+ g_free (path);
+ /* there shouldn't be anything else in there */
+ g_assert_cmpint (g_rmdir (f->tmp_runtime_dir), ==, 0);
+
+ /* we're relying on being single-threaded for this to be safe */
+ if (f->saved_runtime_dir != NULL)
+ g_setenv ("XDG_RUNTIME_DIR", f->saved_runtime_dir, TRUE);
+ else
+ g_unsetenv ("XDG_RUNTIME_DIR");
+ g_free (f->saved_runtime_dir);
+ g_free (f->tmp_runtime_dir);
+ }
+
test_main_context_unref (f->ctx);
}
static Config limited_config = {
- "34393", 10000, "valid-config-files/incoming-limit.conf"
+ "34393", 10000, "valid-config-files/incoming-limit.conf",
+ SPECIFY_ADDRESS
+};
+
+static Config finite_timeout_config = {
+ NULL, 1, "valid-config-files/finite-timeout.conf",
+ SPECIFY_ADDRESS
};
+#ifdef DBUS_UNIX
+static Config listen_unix_runtime_config = {
+ "61303", 1, "valid-config-files/listen-unix-runtime.conf",
+ RELY_ON_DEFAULT
+};
+#endif
+
int
main (int argc,
char **argv)
{
- g_test_init (&argc, &argv, NULL);
- g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id=");
+ test_init (&argc, &argv);
g_test_add ("/echo/session", Fixture, NULL, setup, test_echo, teardown);
g_test_add ("/echo/limited", Fixture, &limited_config,
setup, test_echo, teardown);
+ g_test_add ("/no-reply/disconnect", Fixture, NULL,
+ setup, test_no_reply, teardown);
+ g_test_add ("/no-reply/timeout", Fixture, &finite_timeout_config,
+ setup, test_no_reply, teardown);
g_test_add ("/creds", Fixture, NULL, setup, test_creds, teardown);
+ g_test_add ("/processid", Fixture, NULL, setup, test_processid, teardown);
g_test_add ("/canonical-path/uae", Fixture, NULL,
setup, test_canonical_path_uae, teardown);
+#ifdef DBUS_UNIX
+ /* We can't test this in loopback.c with the rest of unix:runtime=yes,
+ * because dbus_bus_get[_private] is the only way to use the default,
+ * and that blocks on a round-trip to the dbus-daemon */
+ g_test_add ("/unix-runtime-is-default", Fixture, &listen_unix_runtime_config,
+ setup, test_echo, teardown);
+#endif
return g_test_run ();
}
diff --git a/test/fdpass.c b/test/fdpass.c
new file mode 100644
index 00000000..a74ce814
--- /dev/null
+++ b/test/fdpass.c
@@ -0,0 +1,868 @@
+/*
+ * Copyright © 2010-2012 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * 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 AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-internals.h>
+#include <dbus/dbus-sysdeps.h>
+
+#include <glib.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef G_OS_UNIX
+# include <dbus/dbus-sysdeps-unix.h>
+
+# include <errno.h>
+# include <fcntl.h>
+# ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+# endif
+# include <sys/stat.h>
+# include <sys/time.h>
+# include <sys/types.h>
+# include <unistd.h>
+#endif
+
+#include "test-utils-glib.h"
+
+/* Arbitrary; included here to avoid relying on the default */
+#define MAX_MESSAGE_UNIX_FDS 20
+/* This test won't work on Linux unless this is true. */
+_DBUS_STATIC_ASSERT (MAX_MESSAGE_UNIX_FDS <= 253);
+
+/* Arbitrary; included here to avoid relying on the default. */
+#define MAX_INCOMING_UNIX_FDS (MAX_MESSAGE_UNIX_FDS * 4)
+
+/* Arbitrary, except that MAX_MESSAGE_UNIX_FDS * SOME_MESSAGES should be
+ * less than the process's file descriptor limit. */
+#define SOME_MESSAGES 20
+/* To cover some situations on Linux we want this to be true. */
+_DBUS_STATIC_ASSERT (MAX_MESSAGE_UNIX_FDS * SOME_MESSAGES > 256);
+
+/* Linux won't allow more than 253 fds per sendmsg(). */
+#define TOO_MANY_FDS 255
+_DBUS_STATIC_ASSERT (MAX_MESSAGE_UNIX_FDS < TOO_MANY_FDS);
+
+/* As in test/relay.c, this is a miniature dbus-daemon: we relay messages
+ * from the client on the left to the client on the right.
+ *
+ * left socket left dispatch right socket right
+ * client ===========> server --------------> server ===========> client
+ * conn conn conn conn
+ */
+
+typedef struct {
+ TestMainContext *ctx;
+ DBusError e;
+
+ DBusServer *server;
+
+ DBusConnection *left_client_conn;
+ DBusConnection *left_server_conn;
+
+ DBusConnection *right_server_conn;
+ DBusConnection *right_client_conn;
+ /* queue of DBusMessage received by right_client_conn */
+ GQueue messages;
+
+ int fd_before;
+} Fixture;
+
+#ifdef HAVE_UNIX_FD_PASSING
+
+static void oom (const gchar *doing) G_GNUC_NORETURN;
+
+static void
+oom (const gchar *doing)
+{
+ g_error ("out of memory (%s)", doing);
+ abort ();
+}
+
+static void
+assert_no_error (const DBusError *e)
+{
+ if (G_UNLIKELY (dbus_error_is_set (e)))
+ g_error ("expected success but got error: %s: %s", e->name, e->message);
+}
+
+static DBusHandlerResult
+left_server_message_cb (DBusConnection *server_conn,
+ DBusMessage *message,
+ void *data)
+{
+ Fixture *f = data;
+
+ g_assert (server_conn == f->left_server_conn);
+ g_assert (f->right_server_conn != NULL);
+
+ dbus_connection_send (f->right_server_conn, message, NULL);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+right_client_message_cb (DBusConnection *client_conn,
+ DBusMessage *message,
+ void *data)
+{
+ Fixture *f = data;
+
+ g_assert (client_conn == f->right_client_conn);
+ g_queue_push_tail (&f->messages, dbus_message_ref (message));
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static void
+new_conn_cb (DBusServer *server,
+ DBusConnection *server_conn,
+ void *data)
+{
+ Fixture *f = data;
+
+ dbus_connection_set_max_message_unix_fds (server_conn,
+ MAX_MESSAGE_UNIX_FDS);
+ dbus_connection_set_max_received_unix_fds (server_conn,
+ MAX_INCOMING_UNIX_FDS);
+
+ if (f->left_server_conn == NULL)
+ {
+ f->left_server_conn = dbus_connection_ref (server_conn);
+
+ if (!dbus_connection_add_filter (server_conn,
+ left_server_message_cb, f, NULL))
+ oom ("adding filter");
+ }
+ else
+ {
+ g_assert (f->right_server_conn == NULL);
+ f->right_server_conn = dbus_connection_ref (server_conn);
+ }
+
+ test_connection_setup (f->ctx, server_conn);
+}
+
+static void
+test_connect (Fixture *f,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ char *address;
+
+ g_assert (f->left_server_conn == NULL);
+ g_assert (f->right_server_conn == NULL);
+
+ address = dbus_server_get_address (f->server);
+ g_assert (address != NULL);
+
+ f->left_client_conn = dbus_connection_open_private (address, &f->e);
+ assert_no_error (&f->e);
+ g_assert (f->left_client_conn != NULL);
+ test_connection_setup (f->ctx, f->left_client_conn);
+
+ /* The left client connection is allowed to behave abusively. */
+ dbus_connection_set_max_message_unix_fds (f->left_client_conn, 1000);
+ dbus_connection_set_max_received_unix_fds (f->left_client_conn, 1000000);
+
+ while (f->left_server_conn == NULL)
+ {
+ test_progress ('.');
+ test_main_context_iterate (f->ctx, TRUE);
+ }
+
+ f->right_client_conn = dbus_connection_open_private (address, &f->e);
+ assert_no_error (&f->e);
+ g_assert (f->right_client_conn != NULL);
+ test_connection_setup (f->ctx, f->right_client_conn);
+
+ dbus_free (address);
+
+ while (f->right_server_conn == NULL)
+ {
+ test_progress ('.');
+ test_main_context_iterate (f->ctx, TRUE);
+ }
+
+ if (!dbus_connection_add_filter (f->right_client_conn,
+ right_client_message_cb, f, NULL))
+ oom ("adding filter");
+
+ /* The right client connection is allowed to queue all the messages. */
+ dbus_connection_set_max_message_unix_fds (f->right_client_conn, 1000);
+ dbus_connection_set_max_received_unix_fds (f->right_client_conn, 1000000);
+
+ while (!dbus_connection_get_is_authenticated (f->left_client_conn) ||
+ !dbus_connection_get_is_authenticated (f->right_client_conn) ||
+ !dbus_connection_get_is_authenticated (f->left_server_conn) ||
+ !dbus_connection_get_is_authenticated (f->right_server_conn))
+ {
+ test_progress ('*');
+ test_main_context_iterate (f->ctx, TRUE);
+ }
+
+ if (!dbus_connection_can_send_type (f->left_client_conn,
+ DBUS_TYPE_UNIX_FD))
+ g_error ("left client connection cannot send Unix fds");
+
+ if (!dbus_connection_can_send_type (f->left_server_conn,
+ DBUS_TYPE_UNIX_FD))
+ g_error ("left server connection cannot send Unix fds");
+
+ if (!dbus_connection_can_send_type (f->right_client_conn,
+ DBUS_TYPE_UNIX_FD))
+ g_error ("right client connection cannot send Unix fds");
+
+ if (!dbus_connection_can_send_type (f->right_server_conn,
+ DBUS_TYPE_UNIX_FD))
+ g_error ("right server connection cannot send Unix fds");
+}
+#endif
+
+static void
+setup (Fixture *f,
+ gconstpointer data G_GNUC_UNUSED)
+{
+#ifdef HAVE_UNIX_FD_PASSING
+ /* We assume that anything with fd-passing supports the unix: transport */
+
+ f->ctx = test_main_context_get ();
+ dbus_error_init (&f->e);
+ g_queue_init (&f->messages);
+
+ f->server = dbus_server_listen ("unix:tmpdir=/tmp", &f->e);
+ assert_no_error (&f->e);
+ g_assert (f->server != NULL);
+
+ dbus_server_set_new_connection_function (f->server,
+ new_conn_cb, f, NULL);
+ test_server_setup (f->ctx, f->server);
+
+ f->fd_before = open ("/dev/null", O_RDONLY);
+
+ /* this should succeed on any reasonable Unix */
+ if (f->fd_before < 0)
+ g_error ("cannot open /dev/null for reading: %s", g_strerror (errno));
+
+ _dbus_fd_set_close_on_exec (f->fd_before);
+#endif
+}
+
+static void
+test_relay (Fixture *f,
+ gconstpointer data)
+{
+#ifdef HAVE_UNIX_FD_PASSING
+ /* We assume that any platform with working fd-passing is POSIX,
+ * and therefore has open() and fstat() */
+ dbus_uint32_t serial;
+ DBusMessage *outgoing, *incoming;
+ int fd_after;
+ struct stat stat_before;
+ struct stat stat_after;
+
+ test_connect (f, data);
+
+ outgoing = dbus_message_new_signal ("/com/example/Hello",
+ "com.example.Hello", "Greeting");
+ g_assert (outgoing != NULL);
+
+ if (!dbus_message_append_args (outgoing,
+ DBUS_TYPE_UNIX_FD, &f->fd_before,
+ DBUS_TYPE_INVALID))
+ oom ("appending fd");
+
+ if (!dbus_connection_send (f->left_client_conn, outgoing, &serial))
+ oom ("sending message");
+
+ dbus_message_unref (outgoing);
+
+ while (g_queue_get_length (&f->messages) < 1)
+ {
+ test_progress ('.');
+ test_main_context_iterate (f->ctx, TRUE);
+ }
+
+ g_assert_cmpuint (g_queue_get_length (&f->messages), ==, 1);
+
+ incoming = g_queue_pop_head (&f->messages);
+
+ g_assert (dbus_message_contains_unix_fds (incoming));
+ g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL);
+ g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL);
+ g_assert_cmpstr (dbus_message_get_interface (incoming), ==,
+ "com.example.Hello");
+ g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Greeting");
+ g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL);
+ g_assert_cmpstr (dbus_message_get_signature (incoming), ==,
+ DBUS_TYPE_UNIX_FD_AS_STRING);
+ g_assert_cmpstr (dbus_message_get_path (incoming), ==, "/com/example/Hello");
+ g_assert_cmpuint (dbus_message_get_serial (incoming), ==, serial);
+
+ if (!dbus_message_get_args (incoming,
+ &f->e,
+ DBUS_TYPE_UNIX_FD, &fd_after,
+ DBUS_TYPE_INVALID))
+ g_error ("%s: %s", f->e.name, f->e.message);
+
+ assert_no_error (&f->e);
+
+ if (fstat (f->fd_before, &stat_before) < 0)
+ g_error ("%s", g_strerror (errno));
+
+ if (fstat (fd_after, &stat_after) < 0)
+ g_error ("%s", g_strerror (errno));
+
+ /* this seems like enough to say "it's the same file" */
+ g_assert_cmpint (stat_before.st_dev, ==, stat_after.st_dev);
+ g_assert_cmpint (stat_before.st_ino, ==, stat_after.st_ino);
+ g_assert_cmpint (stat_before.st_rdev, ==, stat_after.st_rdev);
+
+ dbus_message_unref (incoming);
+
+ if (close (fd_after) < 0)
+ g_error ("%s", g_strerror (errno));
+
+ g_assert (dbus_connection_get_is_connected (f->right_client_conn));
+ g_assert (dbus_connection_get_is_connected (f->right_server_conn));
+ g_assert (dbus_connection_get_is_connected (f->left_client_conn));
+ g_assert (dbus_connection_get_is_connected (f->left_server_conn));
+#else
+ g_test_skip ("fd-passing not supported on this platform");
+#endif
+}
+
+static void
+test_limit (Fixture *f,
+ gconstpointer data)
+{
+#ifdef HAVE_UNIX_FD_PASSING
+ dbus_uint32_t serial;
+ DBusMessage *outgoing, *incoming;
+ int i;
+
+ test_connect (f, data);
+
+ outgoing = dbus_message_new_signal ("/com/example/Hello",
+ "com.example.Hello", "Greeting");
+ g_assert (outgoing != NULL);
+
+ for (i = 0; i < MAX_MESSAGE_UNIX_FDS; i++)
+ {
+ if (!dbus_message_append_args (outgoing,
+ DBUS_TYPE_UNIX_FD, &f->fd_before,
+ DBUS_TYPE_INVALID))
+ oom ("appending fd");
+ }
+
+ if (!dbus_connection_send (f->left_client_conn, outgoing, &serial))
+ oom ("sending message");
+
+ dbus_message_unref (outgoing);
+
+ while (g_queue_get_length (&f->messages) < 1)
+ {
+ test_progress ('.');
+ test_main_context_iterate (f->ctx, TRUE);
+ }
+
+ g_assert_cmpuint (g_queue_get_length (&f->messages), ==, 1);
+
+ incoming = g_queue_pop_head (&f->messages);
+
+ g_assert (dbus_message_contains_unix_fds (incoming));
+ g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL);
+ g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL);
+ g_assert_cmpstr (dbus_message_get_interface (incoming), ==,
+ "com.example.Hello");
+ g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Greeting");
+ g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL);
+ g_assert_cmpstr (dbus_message_get_path (incoming), ==, "/com/example/Hello");
+ g_assert_cmpuint (dbus_message_get_serial (incoming), ==, serial);
+
+ dbus_message_unref (incoming);
+
+ g_assert (dbus_connection_get_is_connected (f->right_client_conn));
+ g_assert (dbus_connection_get_is_connected (f->right_server_conn));
+ g_assert (dbus_connection_get_is_connected (f->left_client_conn));
+ g_assert (dbus_connection_get_is_connected (f->left_server_conn));
+#else
+ g_test_skip ("fd-passing not supported on this platform");
+#endif
+}
+
+static void
+test_too_many (Fixture *f,
+ gconstpointer data)
+{
+#ifdef HAVE_UNIX_FD_PASSING
+ DBusMessage *outgoing;
+ unsigned int i;
+
+ test_connect (f, data);
+
+ outgoing = dbus_message_new_signal ("/com/example/Hello",
+ "com.example.Hello", "Greeting");
+ g_assert (outgoing != NULL);
+
+ for (i = 0; i < MAX_MESSAGE_UNIX_FDS + GPOINTER_TO_UINT (data); i++)
+ {
+ if (!dbus_message_append_args (outgoing,
+ DBUS_TYPE_UNIX_FD, &f->fd_before,
+ DBUS_TYPE_INVALID))
+ oom ("appending fd");
+ }
+
+ if (!dbus_connection_send (f->left_client_conn, outgoing, NULL))
+ oom ("sending message");
+
+ dbus_message_unref (outgoing);
+
+ /* The sender is unceremoniously disconnected. */
+ while (dbus_connection_get_is_connected (f->left_client_conn) ||
+ dbus_connection_get_is_connected (f->left_server_conn))
+ {
+ test_progress ('.');
+ test_main_context_iterate (f->ctx, TRUE);
+ }
+
+ /* The message didn't get through without its fds. */
+ g_assert_cmpuint (g_queue_get_length (&f->messages), ==, 0);
+
+ /* The intended victim is unaffected by the left connection's
+ * misbehaviour. */
+ g_assert (dbus_connection_get_is_connected (f->right_client_conn));
+ g_assert (dbus_connection_get_is_connected (f->right_server_conn));
+#else
+ g_test_skip ("fd-passing not supported on this platform");
+#endif
+}
+
+static void
+test_too_many_split (Fixture *f,
+ gconstpointer data)
+{
+#ifdef HAVE_UNIX_FD_PASSING
+ DBusMessage *outgoing;
+ int i;
+ DBusSocket left_client_socket;
+ char *payload;
+ int payload_len;
+ DBusString buffer;
+ int fds[TOO_MANY_FDS];
+ int done;
+
+ /* This test deliberately pushes up against OS limits, so skip it
+ * if we don't have enough fds. 4 times the maximum per message
+ * ought to be enough: that will cover the message, the dup'd fds
+ * we actually send, the copy that we potentially receive, and some
+ * spare capacity for everything else. */
+#ifdef HAVE_GETRLIMIT
+ struct rlimit lim;
+
+ if (getrlimit (RLIMIT_NOFILE, &lim) == 0)
+ {
+ if (lim.rlim_cur != RLIM_INFINITY &&
+ lim.rlim_cur < 4 * TOO_MANY_FDS)
+ {
+ g_test_skip ("not enough RLIMIT_NOFILE");
+ return;
+ }
+ }
+#endif
+
+ test_connect (f, data);
+
+ outgoing = dbus_message_new_signal ("/com/example/Hello",
+ "com.example.Hello", "Greeting");
+ g_assert (outgoing != NULL);
+
+ /* TOO_MANY_FDS fds are far too many: in particular, Linux doesn't allow
+ * sending this many in a single sendmsg(). libdbus never splits
+ * a message between two sendmsg() calls if it can help it, and
+ * in particular it always sends all the fds with the first sendmsg(),
+ * but malicious senders might not be so considerate. */
+ for (i = 0; i < TOO_MANY_FDS; i++)
+ {
+ if (!dbus_message_append_args (outgoing,
+ DBUS_TYPE_UNIX_FD, &f->fd_before,
+ DBUS_TYPE_INVALID))
+ oom ("appending fd");
+ }
+
+ /* This probably shouldn't work for messages with fds, but it does,
+ * which is convenient for this sort of trickery. */
+ if (!dbus_message_marshal (outgoing, &payload, &payload_len))
+ oom ("marshalling message");
+
+ _dbus_string_init_const_len (&buffer, payload, payload_len);
+
+ for (i = 0; i < TOO_MANY_FDS; i++)
+ {
+ fds[i] = dup (f->fd_before);
+
+ if (fds[i] < 0)
+ g_error ("could not dup fd: %s", g_strerror (errno));
+ }
+
+ /* This is blatant cheating, and the API documentation specifically
+ * tells you not use this function in this way. Never do this
+ * in application code. */
+ if (!dbus_connection_get_socket (f->left_client_conn,
+ &left_client_socket.fd))
+ g_error ("'unix:' DBusConnection should have had a socket");
+
+ /* Just to be sure that we're at a message boundary. */
+ dbus_connection_flush (f->left_client_conn);
+
+ /* We have too many fds for one sendmsg(), so send the first half
+ * (rounding down if odd) with the first byte... */
+ done = _dbus_write_socket_with_unix_fds (left_client_socket, &buffer, 0, 1,
+ &fds[0], TOO_MANY_FDS / 2);
+
+ if (done < 0)
+ g_error ("could not send first byte and first batch of fds: %s",
+ g_strerror (errno));
+
+ /* ... and the second half (rounding up if odd) with the rest of
+ * the message */
+ done = _dbus_write_socket_with_unix_fds (left_client_socket, &buffer, 1,
+ payload_len - 1, &fds[TOO_MANY_FDS / 2],
+ TOO_MANY_FDS - (TOO_MANY_FDS / 2));
+
+ if (done < 0)
+ {
+ g_error ("could not send rest of message and rest of fds: %s",
+ g_strerror (errno));
+ }
+ else if (done < payload_len - 1)
+ {
+ /* For simplicity, assume the socket buffer is big enough for the
+ * whole message, which should be < 2 KiB. If this fails on some
+ * OS, redo this test code to use a proper loop like the real
+ * libdbus does. */
+ g_error ("short write in sendmsg(), fix this test: %d/%d",
+ done, payload_len - 1);
+ }
+
+ dbus_free (payload);
+
+ for (i = 0; i < TOO_MANY_FDS; i++)
+ close (fds[i]);
+
+ dbus_message_unref (outgoing);
+
+ /* The sender is unceremoniously disconnected. */
+ while (dbus_connection_get_is_connected (f->left_client_conn) ||
+ dbus_connection_get_is_connected (f->left_server_conn))
+ {
+ test_progress ('.');
+ test_main_context_iterate (f->ctx, TRUE);
+ }
+
+ /* The message didn't get through without its fds. */
+ g_assert_cmpuint (g_queue_get_length (&f->messages), ==, 0);
+
+ /* The intended victim is unaffected by the left connection's
+ * misbehaviour. */
+ g_assert (dbus_connection_get_is_connected (f->right_client_conn));
+ g_assert (dbus_connection_get_is_connected (f->right_server_conn));
+#else
+ g_test_skip ("fd-passing not supported on this platform");
+#endif
+}
+
+static void
+test_flood (Fixture *f,
+ gconstpointer data)
+{
+#ifdef HAVE_UNIX_FD_PASSING
+ unsigned int i, j;
+ DBusMessage *outgoing[SOME_MESSAGES];
+ dbus_uint32_t serial;
+
+ test_connect (f, data);
+
+ for (j = 0; j < SOME_MESSAGES; j++)
+ {
+ outgoing[j] = dbus_message_new_signal ("/com/example/Hello",
+ "com.example.Hello", "Greeting");
+ g_assert (outgoing[j] != NULL);
+
+ for (i = 0; i < GPOINTER_TO_UINT (data); i++)
+ {
+ if (!dbus_message_append_args (outgoing[j],
+ DBUS_TYPE_UNIX_FD, &f->fd_before,
+ DBUS_TYPE_INVALID))
+ oom ("appending fd");
+ }
+ }
+
+ /* This is in its own loop so we do it as fast as possible */
+ for (j = 0; j < SOME_MESSAGES; j++)
+ {
+ if (!dbus_connection_send (f->left_client_conn, outgoing[j], &serial))
+ oom ("sending message");
+ }
+
+ for (j = 0; j < SOME_MESSAGES; j++)
+ {
+ dbus_message_unref (outgoing[j]);
+ }
+
+ while (g_queue_get_length (&f->messages) < SOME_MESSAGES)
+ {
+ test_progress ('.');
+ test_main_context_iterate (f->ctx, TRUE);
+ }
+
+ g_assert_cmpuint (g_queue_get_length (&f->messages), ==, SOME_MESSAGES);
+
+ for (j = 0; j < SOME_MESSAGES; j++)
+ {
+ DBusMessage *incoming;
+
+ incoming = g_queue_pop_head (&f->messages);
+
+ g_assert (dbus_message_contains_unix_fds (incoming));
+ g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL);
+ g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL);
+ g_assert_cmpstr (dbus_message_get_interface (incoming), ==,
+ "com.example.Hello");
+ g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Greeting");
+ g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL);
+ g_assert_cmpstr (dbus_message_get_path (incoming), ==, "/com/example/Hello");
+
+ dbus_message_unref (incoming);
+ }
+
+ g_assert (dbus_connection_get_is_connected (f->right_client_conn));
+ g_assert (dbus_connection_get_is_connected (f->right_server_conn));
+ g_assert (dbus_connection_get_is_connected (f->left_client_conn));
+ g_assert (dbus_connection_get_is_connected (f->left_server_conn));
+#else
+ g_test_skip ("fd-passing not supported on this platform");
+#endif
+}
+
+static void
+test_odd_limit (Fixture *f,
+ gconstpointer data)
+{
+#ifdef HAVE_UNIX_FD_PASSING
+ DBusMessage *outgoing;
+ int i;
+
+ test_connect (f, data);
+ dbus_connection_set_max_message_unix_fds (f->left_server_conn, 7);
+ dbus_connection_set_max_message_unix_fds (f->right_server_conn, 7);
+
+ outgoing = dbus_message_new_signal ("/com/example/Hello",
+ "com.example.Hello", "Greeting");
+ g_assert (outgoing != NULL);
+
+ for (i = 0; i < 7 + GPOINTER_TO_INT (data); i++)
+ {
+ if (!dbus_message_append_args (outgoing,
+ DBUS_TYPE_UNIX_FD, &f->fd_before,
+ DBUS_TYPE_INVALID))
+ oom ("appending fd");
+ }
+
+ if (!dbus_connection_send (f->left_client_conn, outgoing, NULL))
+ oom ("sending message");
+
+ dbus_message_unref (outgoing);
+
+ if (GPOINTER_TO_INT (data) > 0)
+ {
+ /* The sender is unceremoniously disconnected. */
+ while (dbus_connection_get_is_connected (f->left_client_conn) ||
+ dbus_connection_get_is_connected (f->left_server_conn))
+ {
+ test_progress ('.');
+ test_main_context_iterate (f->ctx, TRUE);
+ }
+
+ /* The message didn't get through without its fds. */
+ g_assert_cmpuint (g_queue_get_length (&f->messages), ==, 0);
+
+ /* The intended victim is unaffected by the left connection's
+ * misbehaviour. */
+ g_assert (dbus_connection_get_is_connected (f->right_client_conn));
+ g_assert (dbus_connection_get_is_connected (f->right_server_conn));
+ }
+ else
+ {
+ DBusMessage *incoming;
+
+ /* We're at or under the limit. The message gets through intact. */
+ while (g_queue_get_length (&f->messages) < 1)
+ {
+ test_progress ('.');
+ test_main_context_iterate (f->ctx, TRUE);
+ }
+
+ g_assert_cmpuint (g_queue_get_length (&f->messages), ==, 1);
+
+ incoming = g_queue_pop_head (&f->messages);
+
+ g_assert (dbus_message_contains_unix_fds (incoming));
+ g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL);
+ g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL);
+ g_assert_cmpstr (dbus_message_get_interface (incoming), ==,
+ "com.example.Hello");
+ g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Greeting");
+ g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL);
+ g_assert_cmpstr (dbus_message_get_path (incoming), ==,
+ "/com/example/Hello");
+
+ dbus_message_unref (incoming);
+
+ g_assert (dbus_connection_get_is_connected (f->right_client_conn));
+ g_assert (dbus_connection_get_is_connected (f->right_server_conn));
+ g_assert (dbus_connection_get_is_connected (f->left_client_conn));
+ g_assert (dbus_connection_get_is_connected (f->left_server_conn));
+ }
+#else
+ g_test_skip ("fd-passing not supported on this platform");
+#endif
+}
+
+static void
+teardown (Fixture *f,
+ gconstpointer data G_GNUC_UNUSED)
+{
+#ifdef HAVE_UNIX_FD_PASSING
+ if (f->left_client_conn != NULL)
+ {
+ dbus_connection_close (f->left_client_conn);
+ dbus_connection_unref (f->left_client_conn);
+ f->left_client_conn = NULL;
+ }
+
+ if (f->right_client_conn != NULL)
+ {
+ dbus_connection_close (f->right_client_conn);
+ dbus_connection_unref (f->right_client_conn);
+ f->right_client_conn = NULL;
+ }
+
+ if (f->left_server_conn != NULL)
+ {
+ dbus_connection_close (f->left_server_conn);
+ dbus_connection_unref (f->left_server_conn);
+ f->left_server_conn = NULL;
+ }
+
+ if (f->right_server_conn != NULL)
+ {
+ dbus_connection_close (f->right_server_conn);
+ dbus_connection_unref (f->right_server_conn);
+ f->right_server_conn = NULL;
+ }
+
+ if (f->server != NULL)
+ {
+ dbus_server_disconnect (f->server);
+ dbus_server_unref (f->server);
+ f->server = NULL;
+ }
+
+ test_main_context_unref (f->ctx);
+
+ if (f->fd_before >= 0 && close (f->fd_before) < 0)
+ g_error ("%s", g_strerror (errno));
+#endif
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ test_init (&argc, &argv);
+
+#ifdef HAVE_GETRLIMIT
+ {
+ struct rlimit lim;
+
+ if (getrlimit (RLIMIT_NOFILE, &lim) < 0)
+ g_error ("Failed to get RLIMIT_NOFILE limit: %s", g_strerror (errno));
+
+ if (lim.rlim_cur != RLIM_INFINITY &&
+ /* only run if we have a fairly generous margin of error
+ * for stdout, stderr, duplicates, the D-Bus connection, etc. */
+ lim.rlim_cur < 2 * MAX_MESSAGE_UNIX_FDS * SOME_MESSAGES)
+ {
+ g_message ("not enough RLIMIT_NOFILE to run this test");
+ /* Autotools exit code for "all skipped" */
+ return 77;
+ }
+ }
+#endif
+
+ g_test_add ("/relay", Fixture, NULL, setup,
+ test_relay, teardown);
+ g_test_add ("/limit", Fixture, NULL, setup,
+ test_limit, teardown);
+
+ g_test_add ("/too-many/plus1", Fixture, GUINT_TO_POINTER (1), setup,
+ test_too_many, teardown);
+ g_test_add ("/too-many/plus2", Fixture, GUINT_TO_POINTER (2), setup,
+ test_too_many, teardown);
+ g_test_add ("/too-many/plus17", Fixture, GUINT_TO_POINTER (17), setup,
+ test_too_many, teardown);
+
+ g_test_add ("/too-many/split", Fixture, NULL, setup,
+ test_too_many_split, teardown);
+
+ g_test_add ("/flood/1", Fixture, GUINT_TO_POINTER (1),
+ setup, test_flood, teardown);
+#if MAX_MESSAGE_UNIX_FDS >= 2
+ g_test_add ("/flood/half-limit", Fixture,
+ GUINT_TO_POINTER (MAX_MESSAGE_UNIX_FDS / 2),
+ setup, test_flood, teardown);
+#endif
+#if MAX_MESSAGE_UNIX_FDS >= 4
+ g_test_add ("/flood/over-half-limit", Fixture,
+ GUINT_TO_POINTER (3 * MAX_MESSAGE_UNIX_FDS / 4),
+ setup, test_flood, teardown);
+#endif
+ g_test_add ("/flood/limit", Fixture,
+ GUINT_TO_POINTER (MAX_MESSAGE_UNIX_FDS), setup, test_flood, teardown);
+
+ g_test_add ("/odd-limit/minus1", Fixture, GINT_TO_POINTER (-1), setup,
+ test_odd_limit, teardown);
+ g_test_add ("/odd-limit/at", Fixture, GINT_TO_POINTER (0), setup,
+ test_odd_limit, teardown);
+ g_test_add ("/odd-limit/plus1", Fixture, GINT_TO_POINTER (+1), setup,
+ test_odd_limit, teardown);
+ g_test_add ("/odd-limit/plus2", Fixture, GINT_TO_POINTER (+2), setup,
+ test_odd_limit, teardown);
+
+ return g_test_run ();
+}
diff --git a/test/glib-tap-test.sh b/test/glib-tap-test.sh
new file mode 100755
index 00000000..fcb73383
--- /dev/null
+++ b/test/glib-tap-test.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+# Wrapper to make GTest tests output TAP syntax, because Automake's test
+# drivers do not currently support passing the same command-line argument
+# to each test executable. All GTest tests produce TAP output if invoked
+# with the --tap option.
+#
+# Usage: "glib-tap-test.sh test-foo --verbose ..." is equivalent to
+# "test-foo --tap --verbose ..."
+
+set -e
+t="$1"
+shift
+exec "$t" --tap "$@"
diff --git a/test/internals/printf.c b/test/internals/printf.c
index db151518..2006f321 100644
--- a/test/internals/printf.c
+++ b/test/internals/printf.c
@@ -62,20 +62,32 @@ do_test (int minimum,
#define X_TIMES_512 X_TIMES_256 X_TIMES_256
#define X_TIMES_1024 X_TIMES_512 X_TIMES_512
+/* This test outputs TAP syntax: http://testanything.org/ */
int
main (int argc,
char **argv)
{
char buf[] = X_TIMES_1024 X_TIMES_1024 X_TIMES_1024 X_TIMES_1024;
int i;
+ int test_num = 0;
do_test (1, "%d", 0);
+ printf ("ok %d\n", ++test_num);
+
do_test (7, "%d", 1234567);
+ printf ("ok %d\n", ++test_num);
+
do_test (3, "%f", 3.5);
+ printf ("ok %d\n", ++test_num);
do_test (0, "%s", "");
+ printf ("ok %d\n", ++test_num);
+
do_test (1024, "%s", X_TIMES_1024);
+ printf ("ok %d\n", ++test_num);
+
do_test (1025, "%s", X_TIMES_1024 "Y");
+ printf ("ok %d\n", ++test_num);
for (i = 4096; i > 0; i--)
{
@@ -83,6 +95,11 @@ main (int argc,
do_test (i, "%s", buf);
do_test (i + 3, "%s:%d", buf, 42);
}
+ printf ("ok %d\n", ++test_num);
+ /* Tell the TAP driver that we have done all the tests we plan to do.
+ * This is how it can distinguish between an unexpected exit and
+ * successful completion. */
+ printf ("1..%d\n", test_num);
return 0;
}
diff --git a/test/internals/refs.c b/test/internals/refs.c
index 202dc043..7eae44e1 100644
--- a/test/internals/refs.c
+++ b/test/internals/refs.c
@@ -35,7 +35,7 @@
#include <dbus/dbus-message-internal.h>
#include <dbus/dbus-pending-call-internal.h>
#include <dbus/dbus-server-protected.h>
-#include "test-utils.h"
+#include "test-utils-glib.h"
static void
assert_no_error (const DBusError *e)
@@ -585,14 +585,7 @@ int
main (int argc,
char **argv)
{
- /* In GLib >= 2.24, < 2.31 this acts like g_thread_init() but avoids
- * the deprecation of that function. In GLib >= 2.32 this is not
- * necessary at all.
- */
- g_type_init ();
-
- g_test_init (&argc, &argv, NULL);
- g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id=");
+ test_init (&argc, &argv);
g_test_add ("/refs/connection", Fixture, NULL, setup_connection,
test_connection, teardown);
diff --git a/test/internals/syslog.c b/test/internals/syslog.c
index 7e0eae79..805c5784 100644
--- a/test/internals/syslog.c
+++ b/test/internals/syslog.c
@@ -33,6 +33,8 @@
#include <dbus/dbus.h>
#include <dbus/dbus-sysdeps.h>
+#include "test-utils-glib.h"
+
typedef struct {
int dummy;
} Fixture;
@@ -68,16 +70,18 @@ test_syslog (Fixture *f,
{
_dbus_init_system_log (FALSE);
_dbus_system_log (DBUS_SYSTEM_LOG_INFO, MESSAGE "%d", 42);
+ _dbus_system_log (DBUS_SYSTEM_LOG_WARNING, MESSAGE "%d", 45);
_dbus_system_log (DBUS_SYSTEM_LOG_SECURITY, MESSAGE "%d", 666);
exit (0);
}
g_test_trap_assert_passed ();
- g_test_trap_assert_stderr ("*" MESSAGE "42\n*" MESSAGE "666\n*");
+ g_test_trap_assert_stderr ("*" MESSAGE "42\n*" MESSAGE "45\n*" MESSAGE "666\n*");
#endif
/* manual test (this is the best we can do on Windows) */
_dbus_init_system_log (FALSE);
_dbus_system_log (DBUS_SYSTEM_LOG_INFO, MESSAGE "%d", 42);
+ _dbus_system_log (DBUS_SYSTEM_LOG_WARNING, MESSAGE "%d", 45);
_dbus_system_log (DBUS_SYSTEM_LOG_SECURITY, MESSAGE "%d", 666);
}
@@ -91,8 +95,7 @@ int
main (int argc,
char **argv)
{
- g_test_init (&argc, &argv, NULL);
- g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id=");
+ test_init (&argc, &argv);
g_test_add ("/syslog", Fixture, NULL, setup, test_syslog, teardown);
diff --git a/test/loopback.c b/test/loopback.c
index 7526d8d2..bf0542aa 100644
--- a/test/loopback.c
+++ b/test/loopback.c
@@ -2,6 +2,7 @@
*
* Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
* Copyright © 2010-2012 Nokia Corporation
+ * Copyright © 2015 Collabora Ltd.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
@@ -27,12 +28,14 @@
#include <config.h>
#include <glib.h>
+#include <glib/gstdio.h>
#include <dbus/dbus.h>
+#include <errno.h>
#include <string.h>
-#include "test-utils.h"
+#include "test-utils-glib.h"
typedef struct {
TestMainContext *ctx;
@@ -44,6 +47,9 @@ typedef struct {
GQueue server_messages;
DBusConnection *client_conn;
+
+ gchar *tmp_runtime_dir;
+ gchar *saved_runtime_dir;
} Fixture;
static void
@@ -100,6 +106,56 @@ setup (Fixture *f,
test_server_setup (f->ctx, f->server);
}
+#ifdef DBUS_UNIX
+static void
+setup_runtime (Fixture *f,
+ gconstpointer addr)
+{
+ char *listening_at;
+ GError *error = NULL;
+
+ /* this is chosen to be something needing escaping */
+ f->tmp_runtime_dir = g_dir_make_tmp ("dbus=daemon=test.XXXXXX", &error);
+ g_assert_no_error (error);
+
+ /* we're relying on being single-threaded for this to be safe */
+ f->saved_runtime_dir = g_strdup (g_getenv ("XDG_RUNTIME_DIR"));
+ g_setenv ("XDG_RUNTIME_DIR", f->tmp_runtime_dir, TRUE);
+
+ setup (f, addr);
+
+ listening_at = dbus_server_get_address (f->server);
+ g_test_message ("listening at %s", listening_at);
+ g_assert (g_str_has_prefix (listening_at, "unix:path="));
+ g_assert (strstr (listening_at, "dbus%3ddaemon%3dtest.") != NULL);
+ g_assert (strstr (listening_at, "/bus,") != NULL ||
+ g_str_has_suffix (listening_at, "/bus"));
+
+ dbus_free (listening_at);
+}
+
+static void
+setup_no_runtime (Fixture *f,
+ gconstpointer addr)
+{
+ char *listening_at;
+
+ /* we're relying on being single-threaded for this to be safe */
+ f->saved_runtime_dir = g_strdup (g_getenv ("XDG_RUNTIME_DIR"));
+ g_unsetenv ("XDG_RUNTIME_DIR");
+
+ setup (f, addr);
+
+ listening_at = dbus_server_get_address (f->server);
+ g_test_message ("listening at %s", listening_at);
+ /* we have fallen back to something in /tmp, either abstract or not */
+ g_assert (g_str_has_prefix (listening_at, "unix:"));
+ g_assert (strstr (listening_at, "=/tmp/") != NULL);
+
+ dbus_free (listening_at);
+}
+#endif
+
static void
test_connect (Fixture *f,
gconstpointer addr G_GNUC_UNUSED)
@@ -114,7 +170,7 @@ test_connect (Fixture *f,
while (f->server_conn == NULL)
{
- g_print (".");
+ test_progress ('.');
test_main_context_iterate (f->ctx, TRUE);
}
}
@@ -148,7 +204,7 @@ test_bad_guid (Fixture *f,
while (f->server_conn == NULL)
{
- g_print (".");
+ test_progress ('.');
test_main_context_iterate (f->ctx, TRUE);
}
@@ -156,7 +212,7 @@ test_bad_guid (Fixture *f,
while (g_queue_is_empty (&f->server_messages))
{
- g_print (".");
+ test_progress ('.');
test_main_context_iterate (f->ctx, TRUE);
}
@@ -199,7 +255,7 @@ test_message (Fixture *f,
while (g_queue_is_empty (&f->server_messages))
{
- g_print (".");
+ test_progress ('.');
test_main_context_iterate (f->ctx, TRUE);
}
@@ -251,12 +307,51 @@ teardown (Fixture *f,
test_main_context_unref (f->ctx);
}
+#ifdef DBUS_UNIX
+static void
+teardown_no_runtime (Fixture *f,
+ gconstpointer addr)
+{
+ teardown (f, addr);
+
+ /* we're relying on being single-threaded for this to be safe */
+ if (f->saved_runtime_dir != NULL)
+ g_setenv ("XDG_RUNTIME_DIR", f->saved_runtime_dir, TRUE);
+ else
+ g_unsetenv ("XDG_RUNTIME_DIR");
+ g_free (f->saved_runtime_dir);
+}
+
+static void
+teardown_runtime (Fixture *f,
+ gconstpointer addr)
+{
+ gchar *path;
+
+ teardown (f, addr);
+
+ /* the socket may exist */
+ path = g_strdup_printf ("%s/bus", f->tmp_runtime_dir);
+ g_assert (g_remove (path) == 0 || errno == ENOENT);
+ g_free (path);
+ /* there shouldn't be anything else in there */
+ g_assert_cmpint (g_rmdir (f->tmp_runtime_dir), ==, 0);
+
+ /* we're relying on being single-threaded for this to be safe */
+ if (f->saved_runtime_dir != NULL)
+ g_setenv ("XDG_RUNTIME_DIR", f->saved_runtime_dir, TRUE);
+ else
+ g_unsetenv ("XDG_RUNTIME_DIR");
+ g_free (f->saved_runtime_dir);
+ g_free (f->tmp_runtime_dir);
+}
+#endif
+
int
main (int argc,
char **argv)
{
- g_test_init (&argc, &argv, NULL);
- g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id=");
+ test_init (&argc, &argv);
g_test_add ("/connect/tcp", Fixture, "tcp:host=127.0.0.1", setup,
test_connect, teardown);
@@ -273,6 +368,13 @@ main (int argc,
test_connect, teardown);
g_test_add ("/message/unix", Fixture, "unix:tmpdir=/tmp", setup,
test_message, teardown);
+
+ g_test_add ("/connect/unix/runtime", Fixture,
+ "unix:runtime=yes;unix:tmpdir=/tmp", setup_runtime, test_connect,
+ teardown_runtime);
+ g_test_add ("/connect/unix/no-runtime", Fixture,
+ "unix:runtime=yes;unix:tmpdir=/tmp", setup_no_runtime, test_connect,
+ teardown_no_runtime);
#endif
g_test_add ("/message/bad-guid", Fixture, "tcp:host=127.0.0.1", setup,
diff --git a/test/manual-authz.c b/test/manual-authz.c
index f9e3688e..ee9bc52f 100644
--- a/test/manual-authz.c
+++ b/test/manual-authz.c
@@ -30,6 +30,7 @@
#include <dbus/dbus.h>
+#include <stdlib.h>
#ifdef G_OS_UNIX
#include <unistd.h>
#include <sys/types.h>
@@ -57,6 +58,7 @@ static void
oom (void)
{
g_error ("out of memory");
+ abort ();
}
static void
diff --git a/test/manual-dir-iter.c b/test/manual-dir-iter.c
new file mode 100644
index 00000000..21ac0e95
--- /dev/null
+++ b/test/manual-dir-iter.c
@@ -0,0 +1,92 @@
+#include <config.h>
+#include "test-utils.h"
+
+#include "dbus/dbus-macros.h"
+#include "dbus/dbus-sysdeps.h"
+
+static void oom (const char *doing) _DBUS_GNUC_NORETURN;
+static void die (const char *message) _DBUS_GNUC_NORETURN;
+
+void
+oom (const char *doing)
+{
+ fprintf (stderr, "*** manual-dir-iter: OOM while %s\n", doing);
+ exit (1);
+}
+
+void
+die (const char *message)
+{
+ fprintf (stderr, "*** manual-dir-iter: %s\n", message);
+ exit (1);
+}
+
+static void
+debug (const char *message)
+{
+ fprintf (stdout, "+++ manual-dir-iter: %s\n", message);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ DBusString filename;
+ DBusString dirname;
+ DBusError tmp_error;
+ DBusDirIter *dir;
+
+ if (argc != 2)
+ die ("syntax: manual-dir-iter <path>");
+
+ dbus_error_init (&tmp_error);
+
+ if (!_dbus_string_init (&filename))
+ oom ("init filename");
+
+ if (!_dbus_string_init (&dirname))
+ oom ("init dirname");
+
+ _dbus_string_append (&dirname, argv[1]);
+ dir = _dbus_directory_open (&dirname, &tmp_error);
+
+ if (dir == NULL)
+ {
+ fprintf (stderr, "could not open directory: %s: %s\n",
+ tmp_error.name, tmp_error.message);
+ exit(1);
+ }
+
+ while (_dbus_directory_get_next_file (dir, &filename, &tmp_error))
+ {
+ DBusString full_path;
+ if (!_dbus_string_init (&full_path))
+ {
+ oom ("init full_path");
+ }
+
+ if (!_dbus_string_copy (&dirname, 0, &full_path, 0))
+ {
+ oom ("copying full_path to dirname");
+ }
+
+ if (!_dbus_concat_dir_and_file (&full_path, &filename))
+ {
+ oom ("concat full_path");
+ }
+ debug (_dbus_string_get_const_data (&filename));
+ _dbus_string_free (&full_path);
+ }
+
+ if (dbus_error_is_set (&tmp_error))
+ die (tmp_error.message);
+
+ _dbus_string_free (&filename);
+
+ if (dir)
+ _dbus_directory_close (dir);
+
+ _dbus_verbose ("*** Test dir name exiting\n");
+
+ return 0;
+}
diff --git a/test/manual-paths.c b/test/manual-paths.c
new file mode 100644
index 00000000..e392c5c3
--- /dev/null
+++ b/test/manual-paths.c
@@ -0,0 +1,73 @@
+/*
+ * Simple manual paths check
+ *
+ * syntax: manual-paths
+ *
+*/
+
+#include "config.h"
+#include "dbus/dbus-list.h"
+#include "dbus/dbus-internals.h"
+#include "dbus/dbus-sysdeps.h"
+
+#include <stdio.h>
+
+static dbus_bool_t print_install_root()
+{
+ char runtime_prefix[1000];
+
+ if (!_dbus_get_install_root(runtime_prefix, sizeof(runtime_prefix)))
+ {
+ fprintf(stderr, "dbus_get_install_root() failed\n");
+ return FALSE;
+ }
+ fprintf(stdout, "dbus_get_install_root() returned '%s'\n", runtime_prefix);
+ return TRUE;
+}
+
+static dbus_bool_t print_service_dirs()
+{
+ DBusList *dirs;
+ DBusList *link;
+ dirs = NULL;
+
+ if (!_dbus_get_standard_session_servicedirs (&dirs))
+ _dbus_assert_not_reached ("couldn't get standard dirs");
+
+ while ((link = _dbus_list_pop_first_link (&dirs)))
+ {
+ printf ("default service dir: %s\n", (char *)link->data);
+ dbus_free (link->data);
+ _dbus_list_free_link (link);
+ }
+ dbus_free (dirs);
+ return TRUE;
+}
+
+static dbus_bool_t print_replace_install_prefix(const char *s)
+{
+ const char *s2 = _dbus_replace_install_prefix(s);
+ if (!s2)
+ return FALSE;
+
+ fprintf(stdout, "replaced '%s' by '%s'\n", s, s2);
+ return TRUE;
+}
+
+int
+main (int argc, char **argv)
+{
+ if (!print_install_root())
+ return -1;
+
+ if (!print_service_dirs())
+ return -2;
+
+ if (!print_replace_install_prefix(DBUS_BINDIR "/dbus-daemon"))
+ return -3;
+
+ if (!print_replace_install_prefix("c:\\Windows\\System32\\testfile"))
+ return -4;
+
+ return 0;
+}
diff --git a/test/marshal.c b/test/marshal.c
index d74e7671..3353ec00 100644
--- a/test/marshal.c
+++ b/test/marshal.c
@@ -31,6 +31,8 @@
#include <dbus/dbus.h>
+#include "test-utils-glib.h"
+
typedef struct {
DBusError e;
} Fixture;
@@ -248,7 +250,7 @@ main (int argc,
char *aligned_le_blob;
char *aligned_be_blob;
- g_test_init (&argc, &argv, NULL);
+ test_init (&argc, &argv);
/* We have to pass in a buffer that's at least "default aligned",
* i.e. on GNU systems to 8 or 16. The linker may have only given
diff --git a/test/monitor.c b/test/monitor.c
new file mode 100644
index 00000000..c099139a
--- /dev/null
+++ b/test/monitor.c
@@ -0,0 +1,1523 @@
+/* Integration tests for monitor-mode D-Bus connections
+ *
+ * Copyright © 2010-2011 Nokia Corporation
+ * Copyright © 2015 Collabora Ltd.
+ *
+ * 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 AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include "test-utils-glib.h"
+
+typedef struct {
+ const char *config_file;
+ const char * const *match_rules;
+ gboolean care_about_our_names;
+} Config;
+
+typedef struct {
+ const Config *config;
+ TestMainContext *ctx;
+ DBusError e;
+ GError *ge;
+
+ gchar *address;
+ GPid daemon_pid;
+
+ DBusConnection *monitor;
+ DBusConnection *sender;
+ DBusConnection *recipient;
+
+ GQueue monitored;
+
+ const char *monitor_name;
+ const char *sender_name;
+ const char *recipient_name;
+
+ DBusConnection *systemd;
+ const char *systemd_name;
+ DBusMessage *systemd_message;
+ DBusConnection *activated;
+ const char *activated_name;
+ DBusMessage *activated_message;
+} Fixture;
+
+static const char * const no_match_rules[] = {
+ NULL
+};
+
+static const char * const wildcard_match_rules[] = {
+ "",
+ NULL,
+ FALSE
+};
+
+static const char * const eavesdrop_match_rules[] = {
+ "eavesdrop=true",
+ NULL,
+ FALSE
+};
+
+static const char * const no_eavesdrop_match_rules[] = {
+ "eavesdrop=false",
+ NULL,
+ FALSE
+};
+
+static const char * const selective_match_rules[] = {
+ "interface='com.example.Interesting'",
+ "interface='com.example.Fun'",
+ NULL,
+ FALSE
+};
+
+static Config forbidding_config = {
+ "valid-config-files/forbidding.conf",
+ NULL,
+ FALSE
+};
+
+static Config wildcard_config = {
+ NULL,
+ wildcard_match_rules,
+ FALSE
+};
+
+static Config selective_config = {
+ NULL,
+ selective_match_rules,
+ FALSE
+};
+
+static Config no_rules_config = {
+ NULL,
+ no_match_rules,
+ FALSE
+};
+
+static Config eavesdrop_config = {
+ NULL,
+ eavesdrop_match_rules,
+ FALSE
+};
+
+static Config no_eavesdrop_config = {
+ NULL,
+ no_eavesdrop_match_rules,
+ FALSE
+};
+
+static Config fake_systemd_config = {
+ "valid-config-files/systemd-activation.conf",
+ NULL,
+ FALSE
+};
+
+static Config side_effects_config = {
+ NULL,
+ NULL,
+ TRUE
+};
+
+static inline const char *
+not_null2 (const char *x,
+ const char *fallback)
+{
+ if (x == NULL)
+ return fallback;
+
+ return x;
+}
+
+static inline const char *
+not_null (const char *x)
+{
+ return not_null2 (x, "(null)");
+}
+
+#define log_message(m) _log_message (m, __FILE__, __LINE__)
+
+G_GNUC_UNUSED
+static void
+_log_message (DBusMessage *m,
+ const char *file,
+ int line)
+{
+ g_test_message ("%s:%d: message type %d (%s)", file, line,
+ dbus_message_get_type (m),
+ dbus_message_type_to_string (dbus_message_get_type (m)));
+ g_test_message ("\tfrom: %s",
+ not_null2 (dbus_message_get_sender (m), "(dbus-daemon)"));
+ g_test_message ("\tto: %s",
+ not_null2 (dbus_message_get_destination (m), "(broadcast)"));
+ g_test_message ("\tpath: %s",
+ not_null (dbus_message_get_path (m)));
+ g_test_message ("\tinterface: %s",
+ not_null (dbus_message_get_interface (m)));
+ g_test_message ("\tmember: %s",
+ not_null (dbus_message_get_member (m)));
+ g_test_message ("\tsignature: %s",
+ not_null (dbus_message_get_signature (m)));
+ g_test_message ("\terror name: %s",
+ not_null (dbus_message_get_error_name (m)));
+
+ if (strcmp ("s", dbus_message_get_signature (m)) == 0)
+ {
+ DBusError e = DBUS_ERROR_INIT;
+ const char *s;
+
+ dbus_message_get_args (m, &e,
+ DBUS_TYPE_STRING, &s,
+ DBUS_TYPE_INVALID);
+ test_assert_no_error (&e);
+ g_test_message ("\tstring payload: %s", s);
+ }
+}
+
+/* these are macros so they get the right line number */
+
+#define assert_hello(m) \
+do { \
+ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
+ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_METHOD_CALL)); \
+ g_assert_cmpstr (dbus_message_get_destination (m), ==, DBUS_SERVICE_DBUS); \
+ g_assert_cmpstr (dbus_message_get_path (m), ==, DBUS_PATH_DBUS); \
+ g_assert_cmpstr (dbus_message_get_interface (m), ==, DBUS_INTERFACE_DBUS); \
+ g_assert_cmpstr (dbus_message_get_member (m), ==, "Hello"); \
+ g_assert_cmpstr (dbus_message_get_signature (m), ==, ""); \
+ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
+ g_assert_cmpint (dbus_message_get_reply_serial (m), ==, 0); \
+} while (0)
+
+#define assert_hello_reply(m) \
+do { \
+ DBusError _e = DBUS_ERROR_INIT; \
+ const char *_s; \
+ \
+ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
+ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_METHOD_RETURN)); \
+ g_assert_cmpstr (dbus_message_get_sender (m), ==, DBUS_SERVICE_DBUS); \
+ g_assert_cmpstr (dbus_message_get_path (m), ==, NULL); \
+ g_assert_cmpstr (dbus_message_get_interface (m), ==, NULL); \
+ g_assert_cmpstr (dbus_message_get_member (m), ==, NULL); \
+ g_assert_cmpstr (dbus_message_get_signature (m), ==, "s"); \
+ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
+ g_assert_cmpint (dbus_message_get_reply_serial (m), !=, 0); \
+ \
+ dbus_message_get_args (m, &_e, \
+ DBUS_TYPE_STRING, &_s, \
+ DBUS_TYPE_INVALID); \
+ test_assert_no_error (&_e); \
+ g_assert_cmpstr (dbus_message_get_destination (m), ==, _s); \
+} while (0)
+
+#define assert_name_acquired(m) \
+do { \
+ DBusError _e = DBUS_ERROR_INIT; \
+ const char *_s; \
+ \
+ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
+ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_SIGNAL)); \
+ g_assert_cmpstr (dbus_message_get_sender (m), ==, DBUS_SERVICE_DBUS); \
+ g_assert_cmpstr (dbus_message_get_path (m), ==, DBUS_PATH_DBUS); \
+ g_assert_cmpstr (dbus_message_get_interface (m), ==, DBUS_INTERFACE_DBUS); \
+ g_assert_cmpstr (dbus_message_get_member (m), ==, "NameAcquired"); \
+ g_assert_cmpstr (dbus_message_get_signature (m), ==, "s"); \
+ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
+ g_assert_cmpint (dbus_message_get_reply_serial (m), ==, 0); \
+ \
+ dbus_message_get_args (m, &_e, \
+ DBUS_TYPE_STRING, &_s, \
+ DBUS_TYPE_INVALID); \
+ test_assert_no_error (&_e); \
+ g_assert_cmpstr (dbus_message_get_destination (m), ==, _s); \
+} while (0)
+
+#define assert_method_call(m, sender, \
+ destination, path, iface, method, signature) \
+do { \
+ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
+ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_METHOD_CALL)); \
+ g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \
+ g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \
+ g_assert_cmpstr (dbus_message_get_path (m), ==, path); \
+ g_assert_cmpstr (dbus_message_get_interface (m), ==, iface); \
+ g_assert_cmpstr (dbus_message_get_member (m), ==, method); \
+ g_assert_cmpstr (dbus_message_get_signature (m), ==, signature); \
+ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
+ g_assert_cmpint (dbus_message_get_reply_serial (m), ==, 0); \
+} while (0)
+
+#define assert_signal(m, \
+ sender, path, iface, member, signature, \
+ destination) \
+do { \
+ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
+ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_SIGNAL)); \
+ g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \
+ g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \
+ g_assert_cmpstr (dbus_message_get_path (m), ==, path); \
+ g_assert_cmpstr (dbus_message_get_interface (m), ==, iface); \
+ g_assert_cmpstr (dbus_message_get_member (m), ==, member); \
+ g_assert_cmpstr (dbus_message_get_signature (m), ==, signature); \
+ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
+ g_assert_cmpint (dbus_message_get_reply_serial (m), ==, 0); \
+} while (0)
+
+#define assert_method_reply(m, sender, destination, signature) \
+do { \
+ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
+ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_METHOD_RETURN)); \
+ g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \
+ g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \
+ g_assert_cmpstr (dbus_message_get_path (m), ==, NULL); \
+ g_assert_cmpstr (dbus_message_get_interface (m), ==, NULL); \
+ g_assert_cmpstr (dbus_message_get_member (m), ==, NULL); \
+ g_assert_cmpstr (dbus_message_get_signature (m), ==, signature); \
+ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
+ g_assert_cmpint (dbus_message_get_reply_serial (m), !=, 0); \
+} while (0)
+
+#define assert_error_reply(m, sender, destination, error_name) \
+do { \
+ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
+ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_ERROR)); \
+ g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \
+ g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \
+ g_assert_cmpstr (dbus_message_get_error_name (m), ==, error_name); \
+ g_assert_cmpstr (dbus_message_get_path (m), ==, NULL); \
+ g_assert_cmpstr (dbus_message_get_interface (m), ==, NULL); \
+ g_assert_cmpstr (dbus_message_get_member (m), ==, NULL); \
+ g_assert_cmpstr (dbus_message_get_signature (m), ==, "s"); \
+ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
+ g_assert_cmpint (dbus_message_get_reply_serial (m), !=, 0); \
+} while (0)
+
+/* This is called after processing pending replies to our own method
+ * calls, but before anything else.
+ */
+static DBusHandlerResult
+monitor_filter (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ Fixture *f = user_data;
+
+ g_assert_cmpstr (dbus_message_get_interface (message), !=,
+ "com.example.Tedious");
+
+ /* we are not interested in the monitor getting NameAcquired or NameLost
+ * for most tests */
+ if (f->config == NULL || !f->config->care_about_our_names)
+ {
+ if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
+ "NameAcquired") ||
+ dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
+ "NameLost"))
+ {
+ DBusError e = DBUS_ERROR_INIT;
+ const char *s;
+
+ dbus_message_get_args (message, &e,
+ DBUS_TYPE_STRING, &s,
+ DBUS_TYPE_INVALID);
+ test_assert_no_error (&e);
+
+ if (strcmp (s, f->monitor_name) == 0)
+ {
+ /* ignore */
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ }
+ }
+
+ g_queue_push_tail (&f->monitored, dbus_message_ref (message));
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+recipient_filter (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ g_assert_cmpstr (dbus_message_get_interface (message), !=,
+ "com.example.CannotSend");
+ g_assert_cmpstr (dbus_message_get_interface (message), !=,
+ "com.example.CannotReceive");
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult
+systemd_filter (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ Fixture *f = user_data;
+
+ if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
+ "NameAcquired") ||
+ dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
+ "NameLost"))
+ {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ g_assert (f->systemd_message == NULL);
+ f->systemd_message = dbus_message_ref (message);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult
+activated_filter (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ Fixture *f = user_data;
+
+ if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
+ "NameAcquired") ||
+ dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
+ "NameLost"))
+ {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ g_assert (f->activated_message == NULL);
+ f->activated_message = dbus_message_ref (message);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void
+setup (Fixture *f,
+ gconstpointer context)
+{
+ f->config = context;
+
+ f->ctx = test_main_context_get ();
+
+ f->ge = NULL;
+ dbus_error_init (&f->e);
+
+ f->address = test_get_dbus_daemon (f->config ? f->config->config_file : NULL,
+ TEST_USER_ME, &f->daemon_pid);
+
+ if (f->address == NULL)
+ return;
+
+ f->monitor = test_connect_to_bus (f->ctx, f->address);
+ f->monitor_name = dbus_bus_get_unique_name (f->monitor);
+ f->sender = test_connect_to_bus (f->ctx, f->address);
+ f->sender_name = dbus_bus_get_unique_name (f->sender);
+ f->recipient = test_connect_to_bus (f->ctx, f->address);
+ f->recipient_name = dbus_bus_get_unique_name (f->recipient);
+
+ if (!dbus_connection_add_filter (f->monitor, monitor_filter, f, NULL))
+ g_error ("OOM");
+
+ if (!dbus_connection_add_filter (f->recipient, recipient_filter, f, NULL))
+ g_error ("OOM");
+}
+
+static void
+become_monitor (Fixture *f)
+{
+ DBusMessage *m;
+ DBusPendingCall *pc;
+ dbus_bool_t ok;
+ DBusMessageIter appender, array_appender;
+ const char * const *match_rules;
+ int i;
+ dbus_uint32_t zero = 0;
+
+ dbus_connection_set_route_peer_messages (f->monitor, TRUE);
+
+ if (f->config != NULL && f->config->match_rules != NULL)
+ match_rules = f->config->match_rules;
+ else
+ match_rules = wildcard_match_rules;
+
+ m = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS, DBUS_INTERFACE_MONITORING, "BecomeMonitor");
+
+ if (m == NULL)
+ g_error ("OOM");
+
+ dbus_message_iter_init_append (m, &appender);
+
+ if (!dbus_message_iter_open_container (&appender, DBUS_TYPE_ARRAY, "s",
+ &array_appender))
+ g_error ("OOM");
+
+ for (i = 0; match_rules[i] != NULL; i++)
+ {
+ if (!dbus_message_iter_append_basic (&array_appender, DBUS_TYPE_STRING,
+ &match_rules[i]))
+ g_error ("OOM");
+ }
+
+ if (!dbus_message_iter_close_container (&appender, &array_appender) ||
+ !dbus_message_iter_append_basic (&appender, DBUS_TYPE_UINT32, &zero))
+ g_error ("OOM");
+
+ if (!dbus_connection_send_with_reply (f->monitor, m, &pc,
+ DBUS_TIMEOUT_USE_DEFAULT) ||
+ pc == NULL)
+ g_error ("OOM");
+
+ dbus_message_unref (m);
+ m = NULL;
+
+ if (dbus_pending_call_get_completed (pc))
+ test_pending_call_store_reply (pc, &m);
+ else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply,
+ &m, NULL))
+ g_error ("OOM");
+
+ while (m == NULL)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ ok = dbus_message_get_args (m, &f->e,
+ DBUS_TYPE_INVALID);
+ test_assert_no_error (&f->e);
+ g_assert (ok);
+
+ dbus_pending_call_unref (pc);
+ dbus_message_unref (m);
+ m = NULL;
+}
+
+/*
+ * Test the side-effects of becoming a monitor.
+ */
+static void
+test_become_monitor (Fixture *f,
+ gconstpointer context)
+{
+ DBusMessage *m;
+ int ret;
+ dbus_bool_t got_unique = FALSE, got_a = FALSE, got_b = FALSE, got_c = FALSE;
+ dbus_bool_t lost_unique = FALSE, lost_a = FALSE, lost_b = FALSE, lost_c = FALSE;
+
+ if (f->address == NULL)
+ return;
+
+ ret = dbus_bus_request_name (f->monitor, "com.example.A",
+ DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e);
+ test_assert_no_error (&f->e);
+ g_assert_cmpint (ret, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
+
+ ret = dbus_bus_request_name (f->monitor, "com.example.B",
+ DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e);
+ test_assert_no_error (&f->e);
+ g_assert_cmpint (ret, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
+
+ ret = dbus_bus_request_name (f->monitor, "com.example.C",
+ DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e);
+ test_assert_no_error (&f->e);
+ g_assert_cmpint (ret, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
+
+ while (!got_unique || !got_a || !got_b || !got_c)
+ {
+ if (g_queue_is_empty (&f->monitored))
+ test_main_context_iterate (f->ctx, TRUE);
+
+ while ((m = g_queue_pop_head (&f->monitored)) != NULL)
+ {
+ if (dbus_message_is_signal (m, DBUS_INTERFACE_DBUS,
+ "NameAcquired"))
+ {
+ const char *name;
+ dbus_bool_t ok = dbus_message_get_args (m, &f->e,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID);
+
+ g_assert_cmpstr (dbus_message_get_path (m), ==,
+ DBUS_PATH_DBUS);
+
+ test_assert_no_error (&f->e);
+ g_assert (ok);
+
+ if (g_str_equal (name, f->monitor_name))
+ {
+ g_assert (!got_unique);
+ got_unique = TRUE;
+ }
+ else if (g_str_equal (name, "com.example.A"))
+ {
+ g_assert (!got_a);
+ got_a = TRUE;
+ }
+ else if (g_str_equal (name, "com.example.B"))
+ {
+ g_assert (!got_b);
+ got_b = TRUE;
+ }
+ else
+ {
+ g_assert_cmpstr (name, ==, "com.example.C");
+ g_assert (!got_c);
+ got_c = TRUE;
+ }
+ }
+ else
+ {
+ g_error ("unexpected message %s.%s",
+ dbus_message_get_interface (m),
+ dbus_message_get_member (m));
+ }
+
+ dbus_message_unref (m);
+ }
+ }
+
+ become_monitor (f);
+
+ while (!lost_unique || !lost_a || !lost_b || !lost_c)
+ {
+ if (g_queue_is_empty (&f->monitored))
+ test_main_context_iterate (f->ctx, TRUE);
+
+ while ((m = g_queue_pop_head (&f->monitored)) != NULL)
+ {
+ if (dbus_message_is_signal (m, DBUS_INTERFACE_DBUS,
+ "NameLost"))
+ {
+ const char *name;
+ dbus_bool_t ok = dbus_message_get_args (m, &f->e,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID);
+
+ test_assert_no_error (&f->e);
+ g_assert (ok);
+
+ if (g_str_equal (name, f->monitor_name))
+ {
+ g_assert (!lost_unique);
+ lost_unique = TRUE;
+ }
+ else if (g_str_equal (name, "com.example.A"))
+ {
+ g_assert (!lost_a);
+ lost_a = TRUE;
+ }
+ else if (g_str_equal (name, "com.example.B"))
+ {
+ g_assert (!lost_b);
+ lost_b = TRUE;
+ }
+ else
+ {
+ g_assert_cmpstr (name, ==, "com.example.C");
+ g_assert (!lost_c);
+ lost_c = TRUE;
+ }
+ }
+ else
+ {
+ g_error ("unexpected message %s.%s",
+ dbus_message_get_interface (m),
+ dbus_message_get_member (m));
+ }
+
+ dbus_message_unref (m);
+ }
+ }
+
+ /* Calling methods is forbidden; we get disconnected. */
+ dbus_bus_add_match (f->monitor, "", &f->e);
+ g_assert_cmpstr (f->e.name, ==, DBUS_ERROR_NO_REPLY);
+ g_assert (!dbus_connection_get_is_connected (f->monitor));
+
+ while (TRUE)
+ {
+ if (g_queue_is_empty (&f->monitored))
+ test_main_context_iterate (f->ctx, TRUE);
+
+ /* When we iterate all the connection's messages, we see ourselves
+ * losing all our names, then we're disconnected. */
+ while ((m = g_queue_pop_head (&f->monitored)) != NULL)
+ {
+ if (dbus_message_is_signal (m, DBUS_INTERFACE_LOCAL, "Disconnected"))
+ {
+ dbus_message_unref (m);
+ goto disconnected;
+ }
+ else
+ {
+ g_error ("unexpected message %s.%s",
+ dbus_message_get_interface (m),
+ dbus_message_get_member (m));
+ }
+
+ dbus_message_unref (m);
+ }
+ }
+
+disconnected:
+
+ g_assert (lost_a);
+ g_assert (lost_b);
+ g_assert (lost_c);
+}
+
+static void
+test_broadcast (Fixture *f,
+ gconstpointer context)
+{
+ DBusMessage *m;
+
+ if (f->address == NULL)
+ return;
+
+ dbus_bus_add_match (f->recipient, "type='signal'", &f->e);
+ test_assert_no_error (&f->e);
+
+ become_monitor (f);
+
+ m = dbus_message_new_signal ("/foo", "com.example.bar", "BroadcastSignal1");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ m = dbus_message_new_signal ("/foo", "com.example.bar", "BroadcastSignal2");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ m = dbus_message_new_signal ("/foo", "com.example.bar", "BroadcastSignal3");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ while (g_queue_get_length (&f->monitored) < 3)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, f->sender_name, "/foo", "com.example.bar",
+ "BroadcastSignal1", "", NULL);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, f->sender_name, "/foo", "com.example.bar",
+ "BroadcastSignal2", "", NULL);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, f->sender_name, "/foo", "com.example.bar",
+ "BroadcastSignal3", "", NULL);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ g_assert (m == NULL);
+}
+
+static void
+test_forbidden_broadcast (Fixture *f,
+ gconstpointer context)
+{
+ DBusMessage *m;
+
+ if (f->address == NULL)
+ return;
+
+ dbus_bus_add_match (f->recipient, "type='signal'", &f->e);
+ test_assert_no_error (&f->e);
+
+ become_monitor (f);
+
+ m = dbus_message_new_signal ("/foo", "com.example.CannotSend",
+ "BroadcastSignal1");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ m = dbus_message_new_signal ("/foo", "com.example.CannotReceive",
+ "BroadcastSignal2");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ m = dbus_message_new_signal ("/foo", "com.example.CannotSend",
+ "BroadcastSignal3");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ while (g_queue_get_length (&f->monitored) < 6)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, f->sender_name, "/foo", "com.example.CannotSend",
+ "BroadcastSignal1", "", NULL);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
+ DBUS_ERROR_ACCESS_DENIED);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, f->sender_name, "/foo", "com.example.CannotReceive",
+ "BroadcastSignal2", "", NULL);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
+ DBUS_ERROR_ACCESS_DENIED);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, f->sender_name, "/foo", "com.example.CannotSend",
+ "BroadcastSignal3", "", NULL);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
+ DBUS_ERROR_ACCESS_DENIED);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ g_assert (m == NULL);
+}
+
+static void
+test_unicast_signal (Fixture *f,
+ gconstpointer context)
+{
+ DBusMessage *m;
+
+ if (f->address == NULL)
+ return;
+
+ become_monitor (f);
+
+ m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal1");
+ if (!dbus_message_set_destination (m, f->recipient_name))
+ g_error ("OOM");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal2");
+ if (!dbus_message_set_destination (m, f->recipient_name))
+ g_error ("OOM");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal3");
+ if (!dbus_message_set_destination (m, f->recipient_name))
+ g_error ("OOM");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ while (g_queue_get_length (&f->monitored) < 3)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, f->sender_name, "/foo",
+ "com.example.bar", "UnicastSignal1", "", f->recipient_name);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, f->sender_name, "/foo",
+ "com.example.bar", "UnicastSignal2", "", f->recipient_name);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, f->sender_name, "/foo",
+ "com.example.bar", "UnicastSignal3", "", f->recipient_name);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ g_assert (m == NULL);
+}
+
+static void
+test_forbidden (Fixture *f,
+ gconstpointer context)
+{
+ DBusMessage *m;
+
+ if (f->address == NULL)
+ return;
+
+ become_monitor (f);
+
+ m = dbus_message_new_signal ("/foo", "com.example.CannotSend",
+ "UnicastSignal1");
+ if (!dbus_message_set_destination (m, f->recipient_name))
+ g_error ("OOM");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ m = dbus_message_new_signal ("/foo", "com.example.CannotReceive",
+ "UnicastSignal2");
+ if (!dbus_message_set_destination (m, f->recipient_name))
+ g_error ("OOM");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ m = dbus_message_new_signal ("/foo", "com.example.CannotSend",
+ "UnicastSignal3");
+ if (!dbus_message_set_destination (m, f->recipient_name))
+ g_error ("OOM");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ while (g_queue_get_length (&f->monitored) < 6)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, f->sender_name, "/foo",
+ "com.example.CannotSend", "UnicastSignal1", "", f->recipient_name);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
+ DBUS_ERROR_ACCESS_DENIED);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, f->sender_name, "/foo",
+ "com.example.CannotReceive", "UnicastSignal2", "", f->recipient_name);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
+ DBUS_ERROR_ACCESS_DENIED);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, f->sender_name, "/foo",
+ "com.example.CannotSend", "UnicastSignal3", "", f->recipient_name);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
+ DBUS_ERROR_ACCESS_DENIED);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ g_assert (m == NULL);
+}
+
+static void
+test_method_call (Fixture *f,
+ gconstpointer context)
+{
+ DBusMessage *m;
+
+ if (f->address == NULL)
+ return;
+
+ become_monitor (f);
+
+ /* regression test for
+ * https://bugs.freedesktop.org/show_bug.cgi?id=90952 */
+ m = dbus_message_new_method_call (f->recipient_name, "/foo",
+ DBUS_INTERFACE_PEER, "Ping");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ while (g_queue_get_length (&f->monitored) < 2)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_method_call (m, f->sender_name, f->recipient_name, "/foo",
+ DBUS_INTERFACE_PEER, "Ping", "");
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_method_reply (m, f->recipient_name, f->sender_name, "");
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ g_assert (m == NULL);
+
+ m = dbus_message_new_method_call (f->recipient_name, "/foo", "com.example.bar",
+ "Call1");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ while (g_queue_get_length (&f->monitored) < 2)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_method_call (m, f->sender_name, f->recipient_name, "/foo",
+ "com.example.bar", "Call1", "");
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_error_reply (m, f->recipient_name, f->sender_name,
+ DBUS_ERROR_UNKNOWN_METHOD);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ g_assert (m == NULL);
+}
+
+static void
+test_forbidden_method_call (Fixture *f,
+ gconstpointer context)
+{
+ DBusMessage *m;
+
+ if (f->address == NULL)
+ return;
+
+ become_monitor (f);
+
+ m = dbus_message_new_method_call (f->recipient_name, "/foo",
+ "com.example.CannotSend", "Call1");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ while (g_queue_get_length (&f->monitored) < 2)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_method_call (m, f->sender_name, f->recipient_name, "/foo",
+ "com.example.CannotSend", "Call1", "");
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
+ DBUS_ERROR_ACCESS_DENIED);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ g_assert (m == NULL);
+
+ m = dbus_message_new_method_call (f->recipient_name, "/foo",
+ "com.example.CannotReceive", "Call2");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ while (g_queue_get_length (&f->monitored) < 2)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_method_call (m, f->sender_name, f->recipient_name, "/foo",
+ "com.example.CannotReceive", "Call2", "");
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
+ DBUS_ERROR_ACCESS_DENIED);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ g_assert (m == NULL);
+}
+
+static void
+test_dbus_daemon (Fixture *f,
+ gconstpointer context)
+{
+ DBusMessage *m;
+ int res;
+
+ if (f->address == NULL)
+ return;
+
+ become_monitor (f);
+
+ res = dbus_bus_request_name (f->sender, "com.example.Sender",
+ DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e);
+ test_assert_no_error (&f->e);
+ g_assert_cmpint (res, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
+
+ res = dbus_bus_release_name (f->sender, "com.example.Sender", &f->e);
+ test_assert_no_error (&f->e);
+ g_assert_cmpint (res, ==, DBUS_RELEASE_NAME_REPLY_RELEASED);
+
+ while (g_queue_get_length (&f->monitored) < 8)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_method_call (m, f->sender_name, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS, "RequestName", "su");
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS,
+ "NameOwnerChanged", "sss", NULL);
+ dbus_message_unref (m);
+
+ /* FIXME: should we get this? */
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS,
+ "NameAcquired", "s", f->sender_name);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_method_reply (m, DBUS_SERVICE_DBUS, f->sender_name, "u");
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_method_call (m, f->sender_name, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS, "ReleaseName", "s");
+ dbus_message_unref (m);
+
+ /* FIXME: should we get this? */
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS,
+ "NameLost", "s", f->sender_name);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS,
+ "NameOwnerChanged", "sss", NULL);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_method_reply (m, DBUS_SERVICE_DBUS, f->sender_name, "u");
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ g_assert (m == NULL);
+}
+
+static void
+test_selective (Fixture *f,
+ gconstpointer context)
+{
+ DBusMessage *m;
+
+ if (f->address == NULL)
+ return;
+
+ /* Match rules added before becoming a monitor should be cleared:
+ * if they weren't, this test would get Interesting twice, then Tedious,
+ * and only see Fun after that. */
+ dbus_bus_add_match (f->monitor,
+ "eavesdrop='true',interface='com.example.Interesting'", &f->e);
+ test_assert_no_error (&f->e);
+ dbus_bus_add_match (f->monitor,
+ "eavesdrop='true',interface='com.example.Tedious'", &f->e);
+ test_assert_no_error (&f->e);
+
+ become_monitor (f);
+
+ m = dbus_message_new_signal ("/foo", "com.example.Interesting",
+ "UnicastSignal1");
+ if (!dbus_message_set_destination (m, f->recipient_name))
+ g_error ("OOM");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ m = dbus_message_new_signal ("/foo", "com.example.Tedious",
+ "UnicastSignal2");
+ if (!dbus_message_set_destination (m, f->recipient_name))
+ g_error ("OOM");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ m = dbus_message_new_signal ("/foo", "com.example.Fun",
+ "UnicastSignal3");
+ if (!dbus_message_set_destination (m, f->recipient_name))
+ g_error ("OOM");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ while (g_queue_get_length (&f->monitored) < 2)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ /* We get the interesting signal and the fun signal, but not the tedious
+ * signal. */
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, f->sender_name, "/foo",
+ "com.example.Interesting", "UnicastSignal1", "", f->recipient_name);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, f->sender_name, "/foo",
+ "com.example.Fun", "UnicastSignal3", "", f->recipient_name);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ g_assert (m == NULL);
+}
+
+static void
+expect_new_connection (Fixture *f)
+{
+ DBusMessage *m;
+
+ while (g_queue_get_length (&f->monitored) < 4)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_hello (m);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_hello_reply (m);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS,
+ "NameOwnerChanged", "sss", NULL);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_name_acquired (m);
+ dbus_message_unref (m);
+}
+
+static void
+take_well_known_name (Fixture *f,
+ DBusConnection *connection,
+ const char *name)
+{
+ int ret;
+
+ ret = dbus_bus_request_name (connection, name,
+ DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e);
+ test_assert_no_error (&f->e);
+ g_assert_cmpint (ret, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
+}
+
+static void
+expect_take_well_known_name (Fixture *f,
+ DBusConnection *connection,
+ const char *name)
+{
+ DBusMessage *m;
+ const char *connection_name = dbus_bus_get_unique_name (connection);
+
+ while (g_queue_get_length (&f->monitored) < 4)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_method_call (m, connection_name, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS, "RequestName", "su");
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS,
+ "NameOwnerChanged", "sss", NULL);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS,
+ "NameAcquired", "s", connection_name);
+ dbus_message_unref (m);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_method_reply (m, DBUS_SERVICE_DBUS, connection_name, "u");
+ dbus_message_unref (m);
+}
+
+static void
+test_activation (Fixture *f,
+ gconstpointer context)
+{
+ DBusMessage *m;
+
+ if (f->address == NULL)
+ return;
+
+ become_monitor (f);
+
+ /* The sender sends a message to an activatable service. */
+ m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal1");
+ if (!dbus_message_set_destination (m, "com.example.SystemdActivatable1"))
+ g_error ("OOM");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ /* We observe the activation request, and the message that caused it,
+ * before systemd has even joined the bus. */
+ while (g_queue_get_length (&f->monitored) < 2)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+ "org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
+ "org.freedesktop.systemd1");
+ dbus_message_unref (m);
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, f->sender_name, "/foo",
+ "com.example.bar", "UnicastSignal1", "",
+ "com.example.SystemdActivatable1");
+ dbus_message_unref (m);
+
+ /* The fake systemd connects to the bus. */
+ f->systemd = test_connect_to_bus (f->ctx, f->address);
+ if (!dbus_connection_add_filter (f->systemd, systemd_filter, f, NULL))
+ g_error ("OOM");
+ f->systemd_name = dbus_bus_get_unique_name (f->systemd);
+
+ expect_new_connection (f);
+ take_well_known_name (f, f->systemd, "org.freedesktop.systemd1");
+ expect_take_well_known_name (f, f->systemd, "org.freedesktop.systemd1");
+
+ /* It gets its activation request. */
+ while (f->systemd_message == NULL)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = f->systemd_message;
+ f->systemd_message = NULL;
+ assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+ "org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
+ "org.freedesktop.systemd1");
+ dbus_message_unref (m);
+
+ /* systemd starts the activatable service. */
+ f->activated = test_connect_to_bus (f->ctx, f->address);
+ if (!dbus_connection_add_filter (f->activated, activated_filter,
+ f, NULL))
+ g_error ("OOM");
+ f->activated_name = dbus_bus_get_unique_name (f->activated);
+
+ expect_new_connection (f);
+ take_well_known_name (f, f->activated, "com.example.SystemdActivatable1");
+ expect_take_well_known_name (f, f->activated,
+ "com.example.SystemdActivatable1");
+
+ /* The message is delivered to the activatable service. */
+ while (f->activated_message == NULL)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = f->activated_message;
+ f->activated_message = NULL;
+ assert_signal (m, f->sender_name, "/foo",
+ "com.example.bar", "UnicastSignal1", "",
+ "com.example.SystemdActivatable1");
+ dbus_message_unref (m);
+
+ /* The sender sends a message to a different activatable service. */
+ m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal2");
+ if (!dbus_message_set_destination (m, "com.example.SystemdActivatable2"))
+ g_error ("OOM");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ /* This time systemd is already ready for it. */
+ while (g_queue_get_length (&f->monitored) < 2 ||
+ f->systemd_message == NULL)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = f->systemd_message;
+ f->systemd_message = NULL;
+ assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+ "org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
+ "org.freedesktop.systemd1");
+ dbus_message_unref (m);
+
+ /* The monitor sees the activation request and the signal that
+ * prompted it.*/
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+ "org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
+ "org.freedesktop.systemd1");
+ dbus_message_unref (m);
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, f->sender_name, "/foo",
+ "com.example.bar", "UnicastSignal2", "",
+ "com.example.SystemdActivatable2");
+ dbus_message_unref (m);
+
+ /* The activatable service takes its name. Here I'm faking it by using
+ * an existing connection. */
+ take_well_known_name (f, f->activated, "com.example.SystemdActivatable2");
+
+ /* The message is delivered to the activatable service.
+ * Implementation detail: the monitor sees this happen before it even
+ * sees that the name request happened, which is pretty odd. */
+ while (f->activated_message == NULL)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = f->activated_message;
+ f->activated_message = NULL;
+ assert_signal (m, f->sender_name, "/foo",
+ "com.example.bar", "UnicastSignal2", "",
+ "com.example.SystemdActivatable2");
+ dbus_message_unref (m);
+
+ expect_take_well_known_name (f, f->activated,
+ "com.example.SystemdActivatable2");
+
+ /* A third activation. */
+ m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal3");
+ if (!dbus_message_set_destination (m, "com.example.SystemdActivatable3"))
+ g_error ("OOM");
+ dbus_connection_send (f->sender, m, NULL);
+ dbus_message_unref (m);
+
+ /* Once again, we see the activation request and the reason. */
+ while (g_queue_get_length (&f->monitored) < 2)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+ "org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
+ "org.freedesktop.systemd1");
+ dbus_message_unref (m);
+ m = g_queue_pop_head (&f->monitored);
+ assert_signal (m, f->sender_name, "/foo",
+ "com.example.bar", "UnicastSignal3", "",
+ "com.example.SystemdActivatable3");
+ dbus_message_unref (m);
+
+ /* systemd gets the request too. */
+ while (f->systemd_message == NULL)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = f->systemd_message;
+ f->systemd_message = NULL;
+ assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+ "org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
+ "org.freedesktop.systemd1");
+ dbus_message_unref (m);
+
+ /* This time activation fails */
+ m = dbus_message_new_signal ("/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Activator", "ActivationFailure");
+
+ do
+ {
+ const char *unit = "dbus-com.example.SystemdActivatable3.service";
+ const char *error_name = "com.example.Nope";
+ const char *error_message = "Computer says no";
+
+ if (!dbus_message_append_args (m,
+ DBUS_TYPE_STRING, &unit,
+ DBUS_TYPE_STRING, &error_name,
+ DBUS_TYPE_STRING, &error_message,
+ DBUS_TYPE_INVALID))
+ g_error ("OOM");
+ }
+ while (0);
+
+ if (!dbus_message_set_destination (m, "org.freedesktop.DBus"))
+ g_error ("OOM");
+ dbus_connection_send (f->systemd, m, NULL);
+ dbus_message_unref (m);
+
+ /* The monitor sees activation fail */
+
+ /* Once again, we see the activation request and the reason. */
+ while (g_queue_get_length (&f->monitored) < 1)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = g_queue_pop_head (&f->monitored);
+ assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
+ "com.example.Nope");
+ dbus_message_unref (m);
+}
+
+static void
+teardown (Fixture *f,
+ gconstpointer context G_GNUC_UNUSED)
+{
+ dbus_error_free (&f->e);
+ g_clear_error (&f->ge);
+
+ if (f->monitor != NULL)
+ {
+ dbus_connection_remove_filter (f->monitor, monitor_filter, f);
+ dbus_connection_close (f->monitor);
+ dbus_connection_unref (f->monitor);
+ f->monitor = NULL;
+ }
+
+ if (f->sender != NULL)
+ {
+ dbus_connection_close (f->sender);
+ dbus_connection_unref (f->sender);
+ f->sender = NULL;
+ }
+
+ if (f->recipient != NULL)
+ {
+ dbus_connection_remove_filter (f->recipient, recipient_filter, f);
+ dbus_connection_close (f->recipient);
+ dbus_connection_unref (f->recipient);
+ f->recipient = NULL;
+ }
+
+ if (f->systemd != NULL)
+ {
+ dbus_connection_remove_filter (f->systemd, systemd_filter, f);
+ dbus_connection_close (f->systemd);
+ dbus_connection_unref (f->systemd);
+ f->systemd = NULL;
+ }
+
+ if (f->activated != NULL)
+ {
+ dbus_connection_remove_filter (f->activated, activated_filter, f);
+ dbus_connection_close (f->activated);
+ dbus_connection_unref (f->activated);
+ f->activated = NULL;
+ }
+
+ test_kill_pid (f->daemon_pid);
+ g_spawn_close_pid (f->daemon_pid);
+
+ test_main_context_unref (f->ctx);
+
+ g_queue_foreach (&f->monitored, (GFunc) dbus_message_unref, NULL);
+ g_queue_clear (&f->monitored);
+
+ g_free (f->address);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ test_init (&argc, &argv);
+
+ g_test_add ("/monitor/become", Fixture, &side_effects_config,
+ setup, test_become_monitor, teardown);
+ g_test_add ("/monitor/broadcast", Fixture, NULL,
+ setup, test_broadcast, teardown);
+ g_test_add ("/monitor/forbidden-broadcast", Fixture, &forbidding_config,
+ setup, test_forbidden_broadcast, teardown);
+ g_test_add ("/monitor/unicast-signal", Fixture, NULL,
+ setup, test_unicast_signal, teardown);
+ g_test_add ("/monitor/forbidden", Fixture, &forbidding_config,
+ setup, test_forbidden, teardown);
+ g_test_add ("/monitor/method-call", Fixture, NULL,
+ setup, test_method_call, teardown);
+ g_test_add ("/monitor/forbidden-method", Fixture, &forbidding_config,
+ setup, test_forbidden_method_call, teardown);
+ g_test_add ("/monitor/dbus-daemon", Fixture, NULL,
+ setup, test_dbus_daemon, teardown);
+ g_test_add ("/monitor/selective", Fixture, &selective_config,
+ setup, test_selective, teardown);
+ g_test_add ("/monitor/wildcard", Fixture, &wildcard_config,
+ setup, test_unicast_signal, teardown);
+ g_test_add ("/monitor/no-rule", Fixture, &no_rules_config,
+ setup, test_unicast_signal, teardown);
+ g_test_add ("/monitor/eavesdrop", Fixture, &eavesdrop_config,
+ setup, test_unicast_signal, teardown);
+ g_test_add ("/monitor/no-eavesdrop", Fixture, &no_eavesdrop_config,
+ setup, test_unicast_signal, teardown);
+ g_test_add ("/monitor/activation", Fixture, &fake_systemd_config,
+ setup, test_activation, teardown);
+
+ return g_test_run ();
+}
diff --git a/test/name-test/Makefile.am b/test/name-test/Makefile.am
index 8ed1e160..0922558f 100644
--- a/test/name-test/Makefile.am
+++ b/test/name-test/Makefile.am
@@ -1,25 +1,28 @@
-# Everything in this directory is statically-linked to libdbus-internal
AM_CPPFLAGS = \
-I$(top_srcdir) \
+ $(DBUS_STATIC_BUILD_CPPFLAGS) \
-DDBUS_COMPILATION \
- -DDBUS_STATIC_BUILD \
- -DDBUS_TEST_USE_INTERNAL \
$(NULL)
# if assertions are enabled, improve backtraces
AM_LDFLAGS = @R_DYNAMIC_LDFLAG@
+TEST_EXTENSIONS = .sh
+
+SH_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/build-aux/tap-driver.sh
+SH_LOG_COMPILER = $(SHELL)
+
## 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_ENABLE_EMBEDDED_TESTS
-TESTS_ENVIRONMENT = \
- DBUS_TOP_BUILDDIR=@abs_top_builddir@ \
- DBUS_TOP_SRCDIR=@abs_top_srcdir@ \
- PYTHON=@PYTHON@ \
- DBUS_TEST_DATA=@abs_top_builddir@/test/data \
- DBUS_TEST_DAEMON=@abs_top_builddir@/bus/dbus-daemon$(EXEEXT) \
- XDG_RUNTIME_DIR=@abs_top_builddir@/test/XDG_RUNTIME_DIR \
+AM_TESTS_ENVIRONMENT = \
+ export DBUS_TOP_BUILDDIR=@abs_top_builddir@; \
+ export DBUS_TOP_SRCDIR=@abs_top_srcdir@; \
+ export PYTHON=@PYTHON@; \
+ export DBUS_TEST_DATA=@abs_top_builddir@/test/data; \
+ export DBUS_TEST_DAEMON=@abs_top_builddir@/bus/dbus-daemon$(EXEEXT); \
+ export XDG_RUNTIME_DIR=@abs_top_builddir@/test/XDG_RUNTIME_DIR; \
$(NULL)
TESTS=run-test.sh run-test-systemserver.sh
@@ -35,14 +38,14 @@ if DBUS_ENABLE_EMBEDDED_TESTS
## 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-autolaunch
-test_pending_call_dispatch_LDADD=$(top_builddir)/dbus/libdbus-internal.la
-test_pending_call_timeout_LDADD=$(top_builddir)/dbus/libdbus-internal.la
-test_threads_init_LDADD=$(top_builddir)/dbus/libdbus-internal.la
-test_ids_LDADD=$(top_builddir)/dbus/libdbus-internal.la
+test_pending_call_dispatch_LDADD=$(top_builddir)/dbus/libdbus-1.la
+test_pending_call_timeout_LDADD=$(top_builddir)/dbus/libdbus-1.la
+test_threads_init_LDADD=$(top_builddir)/dbus/libdbus-1.la
+test_ids_LDADD=$(top_builddir)/dbus/libdbus-1.la
-test_shutdown_LDADD=../libdbus-testutils-internal.la
-test_privserver_LDADD=../libdbus-testutils-internal.la
-test_privserver_client_LDADD=../libdbus-testutils-internal.la
-test_autolaunch_LDADD=../libdbus-testutils-internal.la
+test_shutdown_LDADD=../libdbus-testutils.la
+test_privserver_LDADD=../libdbus-testutils.la
+test_privserver_client_LDADD=../libdbus-testutils.la
+test_autolaunch_LDADD=../libdbus-testutils.la
endif
diff --git a/test/name-test/run-test-systemserver.sh b/test/name-test/run-test-systemserver.sh
index 90c03723..9926cad6 100755
--- a/test/name-test/run-test-systemserver.sh
+++ b/test/name-test/run-test-systemserver.sh
@@ -1,14 +1,4 @@
#! /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
@@ -27,7 +17,7 @@ if test -z "$DBUS_TEST_NAME_IN_SYS_RUN_TEST"; then
fi
if test -n "$DBUS_TEST_MONITOR"; then
- dbus-monitor --session &
+ dbus-monitor --session >&2 &
fi
XDG_RUNTIME_DIR="$DBUS_TOP_BUILDDIR"/test/XDG_RUNTIME_DIR
@@ -35,22 +25,65 @@ test -d "$XDG_RUNTIME_DIR" || mkdir "$XDG_RUNTIME_DIR"
chmod 0700 "$XDG_RUNTIME_DIR"
export XDG_RUNTIME_DIR
-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
+# Translate a command and exit status into TAP syntax.
+# Usage: interpret_result $? description-of-test
+# Uses global variable $test_num.
+interpret_result () {
+ e="$1"
+ shift
+ case "$e" in
+ (0)
+ echo "ok $test_num $*"
+ ;;
+ (77)
+ echo "ok $test_num # SKIP $*"
+ ;;
+ (*)
+ echo "not ok $test_num $*"
+ ;;
+ esac
+ test_num=$(( $test_num + 1 ))
+}
-echo "running test echo signal"
-if test "x$PYTHON" = "x:"; then
- echo "Skipped test-echo-signal: Python interpreter not found"
-elif ! $PYTHON $DBUS_TOP_SRCDIR/test/name-test/test-wait-for-echo.py; then
- echo "Failed test-wait-for-echo"
- exit 1
-fi
+dbus_send_test () {
+ t="$1"
+ expected_exit="$2"
+ phrase="$3"
+ shift 3
+ e=0
+ echo "# running test $t"
+ "${DBUS_TOP_BUILDDIR}/libtool" --mode=execute $DEBUG "$DBUS_TOP_BUILDDIR/tools/dbus-send" "$@" > output.tmp 2>&1 || e=$?
+ if [ $e != $expected_exit ]; then
+ sed -e 's/^/# /' < output.tmp
+ interpret_result "1" "$t" "$@" "(expected exit status $expected_exit, got $e)"
+ return
+ fi
+ echo "# parsing results of test $t"
+ if ! grep -q "$phrase" output.tmp; then
+ sed -e 's/^/# /' < output.tmp
+ interpret_result "1" "$t" "$@" "(Did not see \"$phrase\" in output)"
+ return
+ fi
+ interpret_result "0" "$t" "$@" "(Saw \"$phrase\" in output as expected)"
+ rm -f output.tmp
+}
+
+py_test () {
+ t="$1"
+ shift
+ if test "x$PYTHON" = "x:"; then
+ interpret_result 77 "$t" "(Python interpreter not found)"
+ else
+ e=0
+ echo "# running test $t"
+ $PYTHON "$DBUS_TOP_SRCDIR/test/name-test/$t" "$@" >&2 || e=$?
+ interpret_result "$e" "$t" "$@"
+ fi
+}
+
+test_num=1
+# TAP syntax: we plan to run 2 tests
+echo "1..2"
-exit 0
+dbus_send_test test-expected-echo-fail 1 DBus.Error --print-reply --dest=org.freedesktop.DBus.TestSuiteEchoService /org/freedesktop/TestSuite org.freedesktop.TestSuite.Echo string:hi
+py_test test-wait-for-echo.py
diff --git a/test/name-test/run-test.sh b/test/name-test/run-test.sh
index 84379c4a..1e257a16 100755
--- a/test/name-test/run-test.sh
+++ b/test/name-test/run-test.sh
@@ -1,17 +1,5 @@
#! /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
@@ -27,7 +15,7 @@ if test -z "$DBUS_TEST_NAME_IN_RUN_TEST"; then
fi
if test -n "$DBUS_TEST_MONITOR"; then
- dbus-monitor --session &
+ dbus-monitor --session >&2 &
fi
XDG_RUNTIME_DIR="$DBUS_TOP_BUILDDIR"/test/XDG_RUNTIME_DIR
@@ -35,31 +23,60 @@ test -d "$XDG_RUNTIME_DIR" || mkdir "$XDG_RUNTIME_DIR"
chmod 0700 "$XDG_RUNTIME_DIR"
export XDG_RUNTIME_DIR
-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"
+# Translate a command and exit status into TAP syntax.
+# Usage: interpret_result $? description-of-test
+# Uses global variable $test_num.
+interpret_result () {
+ e="$1"
+ shift
+ case "$e" in
+ (0)
+ echo "ok $test_num $*"
+ ;;
+ (77)
+ echo "ok $test_num # SKIP $*"
+ ;;
+ (*)
+ echo "not ok $test_num $*"
+ ;;
+ esac
+ test_num=$(( $test_num + 1 ))
+}
-echo "running test-shutdown"
-${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-shutdown || die "test-shutdown failed"
+c_test () {
+ t="$1"
+ shift
+ e=0
+ echo "# running test $t"
+ if ! "${DBUS_TOP_BUILDDIR}/libtool" --mode=execute $DEBUG "$DBUS_TOP_BUILDDIR/test/name-test/$t" "$@" >&2; then
+ e=$?
+ echo "# exit status $e"
+ fi
+ interpret_result "$e" "$t" "$@"
+}
-echo "running test activation forking"
-if test "x$PYTHON" = "x:"; then
- echo "Skipped test-activation-forking: Python interpreter not found"
-elif ! $PYTHON $DBUS_TOP_SRCDIR/test/name-test/test-activation-forking.py; then
- echo "Failed test-activation-forking"
- exit 1
-fi
+py_test () {
+ t="$1"
+ shift
+ if test "x$PYTHON" = "x:"; then
+ interpret_result 77 "$t" "(Python interpreter not found)"
+ else
+ e=0
+ echo "# running test $t"
+ $PYTHON "$DBUS_TOP_SRCDIR/test/name-test/$t" "$@" >&2 || e=$?
+ interpret_result "$e" "$t" "$@"
+ fi
+}
-echo "running test-autolaunch"
-${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-autolaunch || die "test-autolaunch failed"
+test_num=1
+# TAP test plan: we will run 8 tests
+echo "1..8"
+
+c_test test-ids
+c_test test-pending-call-dispatch
+c_test test-pending-call-timeout
+c_test test-threads-init
+c_test test-privserver-client
+c_test test-shutdown
+py_test test-activation-forking.py
+c_test test-autolaunch
diff --git a/test/name-test/test-activation-forking.py b/test/name-test/test-activation-forking.py
index 0d820754..f98537eb 100644
--- a/test/name-test/test-activation-forking.py
+++ b/test/name-test/test-activation-forking.py
@@ -3,7 +3,7 @@
import os,sys
try:
- import gobject
+ from gi.repository import GObject
import dbus
import dbus.mainloop.glib
except:
@@ -11,7 +11,7 @@ except:
sys.exit(0)
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
-loop = gobject.MainLoop()
+loop = GObject.MainLoop()
exitcode = 0
@@ -54,7 +54,7 @@ def check_counter():
if counter == 0:
print "Failed to get NameOwnerChanged for TestSuiteForkingEchoService"
sys.exit(1)
-gobject.timeout_add(15000, check_counter)
+GObject.timeout_add(15000, check_counter)
loop.run()
sys.exit(0)
diff --git a/test/name-test/test-threads-init.c b/test/name-test/test-threads-init.c
index 580ffe14..a517e2a2 100644
--- a/test/name-test/test-threads-init.c
+++ b/test/name-test/test-threads-init.c
@@ -149,16 +149,6 @@ main (int argc, char *argv[])
&dispatch_cond1,
&io_path_cond1);
- /* Since 1.7 it is no longer the case that mutex1 != mutex2, because
- * initializing global locks automatically initializes locks
- * in general. However, it is true that the mutex is not the dummy
- * implementation, which is what we really wanted to check here. */
- _dbus_assert (mutex1 != (DBusMutex *) 0xABCDEF);
- _dbus_assert (dispatch_mutex1 != (DBusMutex *) 0xABCDEF);
- _dbus_assert (dispatch_cond1 != (DBusCondVar *) 0xABCDEF2);
- _dbus_assert (io_path_mutex1 != (DBusMutex *) 0xABCDEF);
- _dbus_assert (io_path_cond1 != (DBusCondVar *) 0xABCDEF2);
-
_run_iteration (conn);
_dbus_connection_test_get_locks (conn, &mutex2,
&dispatch_mutex2,
diff --git a/test/name-test/test-wait-for-echo.py b/test/name-test/test-wait-for-echo.py
index bd09e459..49ecbb46 100755
--- a/test/name-test/test-wait-for-echo.py
+++ b/test/name-test/test-wait-for-echo.py
@@ -3,15 +3,15 @@
import os,sys
try:
- import gobject
import dbus
import dbus.mainloop.glib
+ from gi.repository import GObject
except:
print "Failed import, aborting test"
sys.exit(0)
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
-loop = gobject.MainLoop()
+loop = GObject.MainLoop()
exitcode = 0
@@ -21,7 +21,7 @@ def handle_noreceipt():
exitcode = 1
loop.quit()
-gobject.timeout_add(7000, handle_noreceipt)
+GObject.timeout_add(7000, handle_noreceipt)
bus = dbus.SessionBus()
diff --git a/test/relay.c b/test/relay.c
index 984fde10..e275c167 100644
--- a/test/relay.c
+++ b/test/relay.c
@@ -30,7 +30,7 @@
#include <dbus/dbus.h>
-#include "test-utils.h"
+#include "test-utils-glib.h"
/* This is basically a miniature dbus-daemon. We relay messages from the client
* on the left to the client on the right.
@@ -155,7 +155,7 @@ test_connect (Fixture *f,
while (f->left_server_conn == NULL)
{
- g_print (".");
+ test_progress ('.');
test_main_context_iterate (f->ctx, TRUE);
}
@@ -168,7 +168,7 @@ test_connect (Fixture *f,
while (f->right_server_conn == NULL)
{
- g_print (".");
+ test_progress ('.');
test_main_context_iterate (f->ctx, TRUE);
}
@@ -210,7 +210,7 @@ test_relay (Fixture *f,
while (g_queue_get_length (&f->messages) < 2)
{
- g_print (".");
+ test_progress ('.');
test_main_context_iterate (f->ctx, TRUE);
}
@@ -317,8 +317,7 @@ int
main (int argc,
char **argv)
{
- g_test_init (&argc, &argv, NULL);
- g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id=");
+ test_init (&argc, &argv);
g_test_add ("/connect", Fixture, NULL, setup,
test_connect, teardown);
diff --git a/test/sd-activation.c b/test/sd-activation.c
new file mode 100644
index 00000000..2a7366df
--- /dev/null
+++ b/test/sd-activation.c
@@ -0,0 +1,349 @@
+/* Unit tests for systemd activation.
+ *
+ * Copyright © 2010-2011 Nokia Corporation
+ * Copyright © 2015 Collabora Ltd.
+ *
+ * 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 AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include "test-utils-glib.h"
+
+typedef struct {
+ TestMainContext *ctx;
+ DBusError e;
+ GError *ge;
+
+ gchar *address;
+ GPid daemon_pid;
+
+ DBusConnection *caller;
+ const char *caller_name;
+ DBusConnection *systemd;
+ const char *systemd_name;
+ DBusMessage *systemd_message;
+ DBusConnection *activated;
+ const char *activated_name;
+ DBusMessage *activated_message;
+} Fixture;
+
+/* this is a macro so it gets the right line number */
+#define assert_signal(m, \
+ sender, path, iface, member, signature, \
+ destination) \
+do { \
+ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
+ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_SIGNAL)); \
+ g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \
+ g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \
+ g_assert_cmpstr (dbus_message_get_path (m), ==, path); \
+ g_assert_cmpstr (dbus_message_get_interface (m), ==, iface); \
+ g_assert_cmpstr (dbus_message_get_member (m), ==, member); \
+ g_assert_cmpstr (dbus_message_get_signature (m), ==, signature); \
+ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
+ g_assert_cmpint (dbus_message_get_reply_serial (m), ==, 0); \
+} while (0)
+
+static DBusHandlerResult
+systemd_filter (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ Fixture *f = user_data;
+
+ if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
+ "NameAcquired") ||
+ dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
+ "NameLost"))
+ {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ g_assert (f->systemd_message == NULL);
+ f->systemd_message = dbus_message_ref (message);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult
+activated_filter (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ Fixture *f = user_data;
+
+ if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
+ "NameAcquired") ||
+ dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
+ "NameLost"))
+ {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ g_assert (f->activated_message == NULL);
+ f->activated_message = dbus_message_ref (message);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void
+setup (Fixture *f,
+ gconstpointer context G_GNUC_UNUSED)
+{
+ f->ctx = test_main_context_get ();
+
+ f->ge = NULL;
+ dbus_error_init (&f->e);
+
+ f->address = test_get_dbus_daemon (
+ "valid-config-files/systemd-activation.conf",
+ TEST_USER_ME, &f->daemon_pid);
+
+ if (f->address == NULL)
+ return;
+
+ f->caller = test_connect_to_bus (f->ctx, f->address);
+ f->caller_name = dbus_bus_get_unique_name (f->caller);
+}
+
+static void
+take_well_known_name (Fixture *f,
+ DBusConnection *connection,
+ const char *name)
+{
+ int ret;
+
+ ret = dbus_bus_request_name (connection, name,
+ DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e);
+ test_assert_no_error (&f->e);
+ g_assert_cmpint (ret, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
+}
+
+static void
+test_activation (Fixture *f,
+ gconstpointer context)
+{
+ DBusMessage *m;
+
+ if (f->address == NULL)
+ return;
+
+ /* The sender sends a message to an activatable service. */
+ m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal1");
+ if (!dbus_message_set_destination (m, "com.example.SystemdActivatable1"))
+ g_error ("OOM");
+ dbus_connection_send (f->caller, m, NULL);
+ dbus_message_unref (m);
+
+ /* The fake systemd connects to the bus. */
+ f->systemd = test_connect_to_bus (f->ctx, f->address);
+ if (!dbus_connection_add_filter (f->systemd, systemd_filter, f, NULL))
+ g_error ("OOM");
+ f->systemd_name = dbus_bus_get_unique_name (f->systemd);
+ take_well_known_name (f, f->systemd, "org.freedesktop.systemd1");
+
+ /* It gets its activation request. */
+ while (f->systemd_message == NULL)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = f->systemd_message;
+ f->systemd_message = NULL;
+ assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+ "org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
+ "org.freedesktop.systemd1");
+ dbus_message_unref (m);
+
+ /* systemd starts the activatable service. */
+ f->activated = test_connect_to_bus (f->ctx, f->address);
+ if (!dbus_connection_add_filter (f->activated, activated_filter,
+ f, NULL))
+ g_error ("OOM");
+ f->activated_name = dbus_bus_get_unique_name (f->activated);
+ take_well_known_name (f, f->activated, "com.example.SystemdActivatable1");
+
+ /* The message is delivered to the activatable service. */
+ while (f->activated_message == NULL)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = f->activated_message;
+ f->activated_message = NULL;
+ assert_signal (m, f->caller_name, "/foo",
+ "com.example.bar", "UnicastSignal1", "",
+ "com.example.SystemdActivatable1");
+ dbus_message_unref (m);
+
+ /* The sender sends a message to a different activatable service. */
+ m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal2");
+ if (!dbus_message_set_destination (m, "com.example.SystemdActivatable2"))
+ g_error ("OOM");
+ dbus_connection_send (f->caller, m, NULL);
+ dbus_message_unref (m);
+
+ /* This time systemd is already ready for it. */
+ while (f->systemd_message == NULL)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = f->systemd_message;
+ f->systemd_message = NULL;
+ assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+ "org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
+ "org.freedesktop.systemd1");
+ dbus_message_unref (m);
+
+ /* A malicious process tries to disrupt the activation.
+ * In a more realistic scenario this would be another parallel
+ * connection. */
+ m = dbus_message_new_signal ("/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Activator", "ActivationFailure");
+ if (!dbus_message_set_destination (m, "org.freedesktop.DBus"))
+ g_error ("OOM");
+
+ do
+ {
+ const char *unit = "dbus-com.example.SystemdActivatable2.service";
+ const char *error_name = "com.example.Malice";
+ const char *error_message = "I'm on yr bus, making yr activations fail";
+
+ if (!dbus_message_append_args (m,
+ DBUS_TYPE_STRING, &unit,
+ DBUS_TYPE_STRING, &error_name,
+ DBUS_TYPE_STRING, &error_message,
+ DBUS_TYPE_INVALID))
+ g_error ("OOM");
+ }
+ while (0);
+
+ dbus_connection_send (f->caller, m, NULL);
+ dbus_message_unref (m);
+
+ /* This is just to make sure that the malicious message has arrived and
+ * been processed by the dbus-daemon, i.e. @caller won the race
+ * with @activated. */
+ take_well_known_name (f, f->caller, "com.example.Sync");
+
+ /* The activatable service takes its name. Here I'm faking it by using
+ * an existing connection; in real life it would be yet another
+ * connection. */
+ take_well_known_name (f, f->activated, "com.example.SystemdActivatable2");
+
+ /* The message is delivered to the activatable service. */
+ while (f->activated_message == NULL)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = f->activated_message;
+ f->activated_message = NULL;
+ assert_signal (m, f->caller_name, "/foo",
+ "com.example.bar", "UnicastSignal2", "",
+ "com.example.SystemdActivatable2");
+ dbus_message_unref (m);
+
+ /* A third activation. */
+ m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal3");
+ if (!dbus_message_set_destination (m, "com.example.SystemdActivatable3"))
+ g_error ("OOM");
+ dbus_connection_send (f->caller, m, NULL);
+ dbus_message_unref (m);
+
+ while (f->systemd_message == NULL)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ m = f->systemd_message;
+ f->systemd_message = NULL;
+ assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+ "org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
+ "org.freedesktop.systemd1");
+ dbus_message_unref (m);
+
+ /* This time activation fails */
+ m = dbus_message_new_signal ("/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Activator", "ActivationFailure");
+
+ do
+ {
+ const char *unit = "dbus-com.example.SystemdActivatable3.service";
+ const char *error_name = "com.example.Nope";
+ const char *error_message = "Computer says no";
+
+ if (!dbus_message_append_args (m,
+ DBUS_TYPE_STRING, &unit,
+ DBUS_TYPE_STRING, &error_name,
+ DBUS_TYPE_STRING, &error_message,
+ DBUS_TYPE_INVALID))
+ g_error ("OOM");
+ }
+ while (0);
+
+ if (!dbus_message_set_destination (m, "org.freedesktop.DBus"))
+ g_error ("OOM");
+ dbus_connection_send (f->systemd, m, NULL);
+ dbus_message_unref (m);
+}
+
+static void
+teardown (Fixture *f,
+ gconstpointer context G_GNUC_UNUSED)
+{
+ dbus_error_free (&f->e);
+ g_clear_error (&f->ge);
+
+ if (f->caller != NULL)
+ {
+ dbus_connection_close (f->caller);
+ dbus_connection_unref (f->caller);
+ f->caller = NULL;
+ }
+
+ if (f->systemd != NULL)
+ {
+ dbus_connection_remove_filter (f->systemd, systemd_filter, f);
+ dbus_connection_close (f->systemd);
+ dbus_connection_unref (f->systemd);
+ f->systemd = NULL;
+ }
+
+ if (f->activated != NULL)
+ {
+ dbus_connection_remove_filter (f->activated, activated_filter, f);
+ dbus_connection_close (f->activated);
+ dbus_connection_unref (f->activated);
+ f->activated = NULL;
+ }
+
+ test_kill_pid (f->daemon_pid);
+ g_spawn_close_pid (f->daemon_pid);
+ test_main_context_unref (f->ctx);
+ g_free (f->address);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ test_init (&argc, &argv);
+
+ g_test_add ("/sd-activation", Fixture, NULL,
+ setup, test_activation, teardown);
+
+ return g_test_run ();
+}
diff --git a/test/shell-test.c b/test/shell-test.c
index d1dc5b5b..61280d68 100644
--- a/test/shell-test.c
+++ b/test/shell-test.c
@@ -9,8 +9,13 @@
#include <dbus/dbus-string.h>
#include <dbus/dbus-sysdeps.h>
+static int test_num = 0;
+static int num_failed = 0;
+
static dbus_bool_t
-test_command_line (const char *arg1, ...)
+test_command_line_internal (dbus_bool_t should_work,
+ const char *arg1,
+ va_list var_args)
{
int i, original_argc, shell_argc;
char **shell_argv;
@@ -18,10 +23,8 @@ test_command_line (const char *arg1, ...)
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
{
@@ -30,7 +33,6 @@ test_command_line (const char *arg1, ...)
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);
@@ -46,23 +48,28 @@ test_command_line (const char *arg1, ...)
_dbus_list_clear (&list);
command_line = _dbus_string_get_data (&str);
- printf ("\n\nTesting command line '%s'\n", command_line);
+ printf ("# Testing 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;
+ printf ("# Error%s parsing command line: %s\n",
+ should_work ? "" : " (as expected)",
+ error.message ? error.message : "");
+ dbus_free (original_argv);
+ return !should_work;
}
else
{
if (shell_argc != original_argc)
{
- printf ("Number of arguments returned (%d) don't match original (%d)\n",
+ printf ("# Number of arguments returned (%d) don't match original (%d)\n",
shell_argc, original_argc);
+ dbus_free (original_argv);
+ dbus_free_string_array (shell_argv);
return FALSE;
}
- printf ("Number of arguments: %d\n", shell_argc);
+ printf ("# Number of arguments: %d\n", shell_argc);
for (i = 0; i < shell_argc; i++)
{
char *unquoted;
@@ -74,6 +81,8 @@ test_command_line (const char *arg1, ...)
printf ("Position %d, returned argument (%s) does not match original (%s)\n",
i, shell_argv[i], unquoted);
dbus_free (unquoted);
+ dbus_free (original_argv);
+ dbus_free_string_array (shell_argv);
return FALSE;
}
dbus_free (unquoted);
@@ -83,27 +92,79 @@ test_command_line (const char *arg1, ...)
dbus_free_string_array (shell_argv);
}
-
+
_dbus_string_free (&str);
-
+ dbus_free (original_argv);
+
+ if (!should_work)
+ {
+ printf ("# Expected an error\n");
+ return FALSE;
+ }
+
return TRUE;
}
+static void
+test_command_line (const char *arg1, ...)
+{
+ va_list var_args;
+
+ va_start (var_args, arg1);
+
+ if (test_command_line_internal (TRUE, arg1, var_args))
+ {
+ printf ("ok %d\n", ++test_num);
+ }
+ else
+ {
+ printf ("not ok %d\n", ++test_num);
+ num_failed++;
+ }
+
+ va_end (var_args);
+}
+
+static void
+test_command_line_fails (const char *arg1, ...)
+{
+ va_list var_args;
+
+ va_start (var_args, arg1);
+
+ if (test_command_line_internal (FALSE, arg1, var_args))
+ {
+ printf ("ok %d\n", ++test_num);
+ }
+ else
+ {
+ printf ("not ok %d\n", ++test_num);
+ num_failed++;
+ }
+
+ va_end (var_args);
+}
+
+/* This test outputs TAP syntax: http://testanything.org/ */
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;
+ 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_fails ("ls", "\"a wrong string'", NULL);
+
+ /* Tell the TAP driver that we have done all the tests we plan to do.
+ * This is how it can distinguish between an unexpected exit and
+ * successful completion. */
+ printf ("1..%d\n", test_num);
+
+ return (num_failed != 0);
}
diff --git a/test/syntax.c b/test/syntax.c
index e26b3643..bf960c9e 100644
--- a/test/syntax.c
+++ b/test/syntax.c
@@ -30,6 +30,8 @@
#include <dbus/dbus.h>
+#include "test-utils-glib.h"
+
typedef struct {
DBusError e;
} Fixture;
@@ -269,7 +271,7 @@ int
main (int argc,
char **argv)
{
- g_test_init (&argc, &argv, NULL);
+ test_init (&argc, &argv);
g_test_add ("/syntax/path", Fixture, &paths, setup, test_syntax, teardown);
g_test_add ("/syntax/interface", Fixture, &interfaces,
diff --git a/test/tap-test.sh.in b/test/tap-test.sh.in
new file mode 100644
index 00000000..743cdf39
--- /dev/null
+++ b/test/tap-test.sh.in
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+# Wrapper to make an Automake-style test output TAP syntax:
+#
+# - arbitrary stdout/stderr is sent to stderr where it will not be
+# interpreted as TAP
+# - it is treated as a single test-case
+# - exit 77 is a skip
+# - exit 0 is a pass
+# - anything else is a failure
+#
+# Usage: use sed to replace @RUN@ with the shell command-line to be run.
+
+set -e
+
+# we plan to do 1 test-case
+echo "1..1"
+
+e=0
+@RUN@ >&2 || e=$?
+
+case "$e" in
+ (0)
+ echo "ok 1 @RUN@"
+ ;;
+ (77)
+ echo "ok 1 # SKIP @RUN@"
+ ;;
+ (*)
+ echo "not ok 1 @RUN@ (exit status $e)"
+ ;;
+esac
diff --git a/test/test-service.c b/test/test-service.c
index 7181fa38..c0bd2c60 100644
--- a/test/test-service.c
+++ b/test/test-service.c
@@ -400,20 +400,18 @@ main (int argc,
int result;
DBusConnection *connection;
const char *name;
- dbus_bool_t do_fork;
-
+#ifndef DBUS_WIN
+ dbus_bool_t do_fork = FALSE;
+#endif
if (argc != 3)
{
name = "org.freedesktop.DBus.TestSuiteEchoService";
- do_fork = FALSE;
}
else
{
name = argv[1];
#ifndef DBUS_WIN
do_fork = strcmp (argv[2], "fork") == 0;
-#else
- do_fork = FALSE;
#endif
}
diff --git a/test/test-utils-glib.c b/test/test-utils-glib.c
new file mode 100644
index 00000000..a40c30b7
--- /dev/null
+++ b/test/test-utils-glib.c
@@ -0,0 +1,452 @@
+/* Utility functions for tests that rely on GLib
+ *
+ * Copyright © 2010-2011 Nokia Corporation
+ * Copyright © 2013-2015 Collabora Ltd.
+ *
+ * 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 AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <config.h>
+#include "test-utils-glib.h"
+
+#include <string.h>
+
+#ifdef DBUS_WIN
+# include <io.h>
+# include <windows.h>
+#else
+# include <errno.h>
+# include <signal.h>
+# include <unistd.h>
+# include <sys/types.h>
+# include <pwd.h>
+#endif
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <dbus/dbus.h>
+
+#ifdef G_OS_WIN
+# define isatty(x) _isatty(x)
+#endif
+
+void
+_test_assert_no_error (const DBusError *e,
+ const char *file,
+ int line)
+{
+ if (G_UNLIKELY (dbus_error_is_set (e)))
+ g_error ("%s:%d: expected success but got error: %s: %s",
+ file, line, e->name, e->message);
+}
+
+#ifdef DBUS_UNIX
+static void
+child_setup (gpointer user_data)
+{
+ const struct passwd *pwd = user_data;
+ uid_t uid = geteuid ();
+
+ if (pwd == NULL || (pwd->pw_uid == uid && getuid () == uid))
+ return;
+
+ if (uid != 0)
+ g_error ("not currently euid 0: %lu", (unsigned long) uid);
+
+ if (setuid (pwd->pw_uid) != 0)
+ g_error ("could not setuid (%lu): %s",
+ (unsigned long) pwd->pw_uid, g_strerror (errno));
+
+ uid = getuid ();
+
+ if (uid != pwd->pw_uid)
+ g_error ("after successful setuid (%lu) my uid is %ld",
+ (unsigned long) pwd->pw_uid, (unsigned long) uid);
+
+ uid = geteuid ();
+
+ if (uid != pwd->pw_uid)
+ g_error ("after successful setuid (%lu) my euid is %ld",
+ (unsigned long) pwd->pw_uid, (unsigned long) uid);
+}
+#endif
+
+static gchar *
+spawn_dbus_daemon (const gchar *binary,
+ const gchar *configuration,
+ TestUser user,
+ GPid *daemon_pid)
+{
+ GError *error = NULL;
+ GString *address;
+ gint address_fd;
+ const gchar *const argv[] = {
+ binary,
+ configuration,
+ "--nofork",
+ "--print-address=1", /* stdout */
+#ifdef DBUS_UNIX
+ "--systemd-activation",
+#endif
+ NULL
+ };
+#ifdef DBUS_UNIX
+ const struct passwd *pwd = NULL;
+#endif
+
+ if (user != TEST_USER_ME)
+ {
+#ifdef DBUS_UNIX
+ if (getuid () != 0)
+ {
+ g_test_skip ("cannot use alternative uid when not uid 0");
+ return NULL;
+ }
+
+ switch (user)
+ {
+ case TEST_USER_ROOT:
+ break;
+
+ case TEST_USER_MESSAGEBUS:
+ pwd = getpwnam (DBUS_USER);
+
+ if (pwd == NULL)
+ {
+ gchar *message = g_strdup_printf ("user '%s' does not exist",
+ DBUS_USER);
+
+ g_test_skip (message);
+ g_free (message);
+ return NULL;
+ }
+
+ break;
+
+ case TEST_USER_OTHER:
+ pwd = getpwnam (DBUS_TEST_USER);
+
+ if (pwd == NULL)
+ {
+ gchar *message = g_strdup_printf ("user '%s' does not exist",
+ DBUS_TEST_USER);
+
+ g_test_skip (message);
+ g_free (message);
+ return NULL;
+ }
+
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+#else
+ g_test_skip ("cannot use alternative uid on Windows");
+ return NULL;
+#endif
+ }
+
+ g_spawn_async_with_pipes (NULL, /* working directory */
+ (gchar **) argv, /* g_s_a_w_p() is not const-correct :-( */
+ NULL, /* envp */
+ G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
+#ifdef DBUS_UNIX
+ child_setup, (gpointer) pwd,
+#else
+ NULL, NULL,
+#endif
+ daemon_pid,
+ NULL, /* child's stdin = /dev/null */
+ &address_fd,
+ NULL, /* child's stderr = our stderr */
+ &error);
+ g_assert_no_error (error);
+
+ address = g_string_new (NULL);
+
+ /* polling until the dbus-daemon writes out its address is a bit stupid,
+ * but at least it's simple, unlike dbus-launch... in principle we could
+ * use select() here, but life's too short */
+ while (1)
+ {
+ gssize bytes;
+ gchar buf[4096];
+ gchar *newline;
+
+ bytes = read (address_fd, buf, sizeof (buf));
+
+ if (bytes > 0)
+ g_string_append_len (address, buf, bytes);
+
+ newline = strchr (address->str, '\n');
+
+ if (newline != NULL)
+ {
+ if ((newline > address->str) && ('\r' == newline[-1]))
+ newline -= 1;
+ g_string_truncate (address, newline - address->str);
+ break;
+ }
+
+ g_usleep (G_USEC_PER_SEC / 10);
+ }
+
+ g_close (address_fd, NULL);
+
+ return g_string_free (address, FALSE);
+}
+
+gchar *
+test_get_dbus_daemon (const gchar *config_file,
+ TestUser user,
+ GPid *daemon_pid)
+{
+ gchar *dbus_daemon;
+ gchar *arg;
+ gchar *address;
+
+ if (config_file != NULL)
+ {
+
+ if (g_getenv ("DBUS_TEST_DATA") == NULL)
+ {
+ g_test_message ("set DBUS_TEST_DATA to a directory containing %s",
+ config_file);
+ g_test_skip ("DBUS_TEST_DATA not set");
+ return NULL;
+ }
+
+ arg = g_strdup_printf (
+ "--config-file=%s/%s",
+ g_getenv ("DBUS_TEST_DATA"), config_file);
+ }
+ else if (g_getenv ("DBUS_TEST_DATADIR") != NULL)
+ {
+ arg = g_strdup_printf ("--config-file=%s/dbus-1/session.conf",
+ g_getenv ("DBUS_TEST_DATADIR"));
+ }
+ else if (g_getenv ("DBUS_TEST_DATA") != NULL)
+ {
+ arg = g_strdup_printf (
+ "--config-file=%s/valid-config-files/session.conf",
+ g_getenv ("DBUS_TEST_DATA"));
+ }
+ else
+ {
+ arg = g_strdup ("--session");
+ }
+
+ dbus_daemon = g_strdup (g_getenv ("DBUS_TEST_DAEMON"));
+
+ if (dbus_daemon == NULL)
+ dbus_daemon = g_strdup ("dbus-daemon");
+
+ if (g_getenv ("DBUS_TEST_DAEMON_ADDRESS") != NULL)
+ {
+ if (config_file != NULL || user != TEST_USER_ME)
+ {
+ g_test_skip ("cannot use DBUS_TEST_DAEMON_ADDRESS for "
+ "unusally-configured dbus-daemon");
+ address = NULL;
+ }
+ else
+ {
+ address = g_strdup (g_getenv ("DBUS_TEST_DAEMON_ADDRESS"));
+ }
+ }
+ else
+ {
+ address = spawn_dbus_daemon (dbus_daemon, arg, user, daemon_pid);
+ }
+
+ g_free (dbus_daemon);
+ g_free (arg);
+ return address;
+}
+
+DBusConnection *
+test_connect_to_bus (TestMainContext *ctx,
+ const gchar *address)
+{
+ DBusConnection *conn;
+ DBusError error = DBUS_ERROR_INIT;
+ dbus_bool_t ok;
+
+ conn = dbus_connection_open_private (address, &error);
+ test_assert_no_error (&error);
+ g_assert (conn != NULL);
+
+ ok = dbus_bus_register (conn, &error);
+ test_assert_no_error (&error);
+ g_assert (ok);
+ g_assert (dbus_bus_get_unique_name (conn) != NULL);
+
+ test_connection_setup (ctx, conn);
+ return conn;
+}
+
+DBusConnection *
+test_connect_to_bus_as_user (TestMainContext *ctx,
+ const char *address,
+ TestUser user)
+{
+ /* For now we only do tests like this on Linux, because I don't know how
+ * safe this use of setresuid() is on other platforms */
+#if defined(HAVE_GETRESUID) && defined(HAVE_SETRESUID) && defined(__linux__)
+ uid_t ruid, euid, suid;
+ const struct passwd *pwd;
+ DBusConnection *conn;
+ const char *username;
+
+ switch (user)
+ {
+ case TEST_USER_ME:
+ return test_connect_to_bus (ctx, address);
+
+ case TEST_USER_ROOT:
+ username = "root";
+ break;
+
+ case TEST_USER_MESSAGEBUS:
+ username = DBUS_USER;
+ break;
+
+ case TEST_USER_OTHER:
+ username = DBUS_TEST_USER;
+ break;
+
+ default:
+ g_return_val_if_reached (NULL);
+ }
+
+ if (getresuid (&ruid, &euid, &suid) != 0)
+ g_error ("getresuid: %s", g_strerror (errno));
+
+ if (ruid != 0 || euid != 0 || suid != 0)
+ {
+ g_test_message ("not uid 0 (ruid=%ld euid=%ld suid=%ld)",
+ (unsigned long) ruid, (unsigned long) euid, (unsigned long) suid);
+ g_test_skip ("not uid 0");
+ return NULL;
+ }
+
+ pwd = getpwnam (username);
+
+ if (pwd == NULL)
+ {
+ g_test_message ("getpwnam(\"%s\"): %s", username, g_strerror (errno));
+ g_test_skip ("not uid 0");
+ return NULL;
+ }
+
+ /* Impersonate the desired user while we connect to the bus.
+ * This should work, because we're root. */
+ if (setresuid (pwd->pw_uid, pwd->pw_uid, 0) != 0)
+ g_error ("setresuid(%ld, (same), 0): %s",
+ (unsigned long) pwd->pw_uid, g_strerror (errno));
+
+ conn = test_connect_to_bus (ctx, address);
+
+ /* go back to our saved uid */
+ if (setresuid (0, 0, 0) != 0)
+ g_error ("setresuid(0, 0, 0): %s", g_strerror (errno));
+
+ return conn;
+
+#else
+
+ switch (user)
+ {
+ case TEST_USER_ME:
+ return test_connect_to_bus (ctx, address);
+
+ default:
+ g_test_skip ("setresuid() not available, or unsure about "
+ "credentials-passing semantics on this platform");
+ return NULL;
+ }
+
+#endif
+}
+
+void
+test_kill_pid (GPid pid)
+{
+#ifdef DBUS_WIN
+ if (pid != NULL)
+ TerminateProcess (pid, 1);
+#else
+ if (pid > 0)
+ kill (pid, SIGTERM);
+#endif
+}
+
+static gboolean
+time_out (gpointer data)
+{
+ g_error ("timed out");
+ return FALSE;
+}
+
+#ifdef G_OS_UNIX
+static void
+wrap_abort (int signal)
+{
+ abort ();
+}
+#endif
+
+void
+test_init (int *argcp, char ***argvp)
+{
+ g_test_init (argcp, argvp, NULL);
+ g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id=");
+
+ /* Prevent tests from hanging forever. This is intended to be long enough
+ * that any reasonable regression test on any reasonable hardware would
+ * have finished. */
+#define TIMEOUT 60
+
+ g_timeout_add_seconds (TIMEOUT, time_out, NULL);
+#ifdef G_OS_UNIX
+ /* The GLib main loop might not be running (we don't use it in every
+ * test). Die with SIGALRM shortly after if necessary. */
+ alarm (TIMEOUT + 10);
+
+ /* Get a core dump from the SIGALRM. */
+ {
+ struct sigaction act = { };
+
+ act.sa_handler = wrap_abort;
+
+ sigaction (SIGALRM, &act, NULL);
+ }
+#endif
+}
+
+void
+test_progress (char symbol)
+{
+ if (g_test_verbose () && isatty (1))
+ g_print ("%c", symbol);
+}
diff --git a/test/test-utils-glib.h b/test/test-utils-glib.h
new file mode 100644
index 00000000..acacee0a
--- /dev/null
+++ b/test/test-utils-glib.h
@@ -0,0 +1,94 @@
+/* Utility functions for tests that rely on GLib
+ *
+ * Copyright © 2010-2011 Nokia Corporation
+ * Copyright © 2013-2015 Collabora Ltd.
+ *
+ * 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 AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef TEST_UTILS_GLIB_H
+#define TEST_UTILS_GLIB_H
+
+#include <dbus/dbus.h>
+
+#include <glib.h>
+
+#include "test-utils.h"
+
+/*
+ * Multi-user support for regression tests run with root privileges in
+ * a continuous integration system.
+ *
+ * A developer would normally run the tests as their own uid. Tests run
+ * as TEST_USER_ME are run, and the others are skipped.
+ *
+ * In a CI system that has access to root privileges, most tests should still
+ * be run as an arbitrary non-root user, as above.
+ *
+ * Certain tests can usefully be run again, as root. When this is done,
+ * tests using TEST_USER_ROOT, TEST_USER_MESSAGEBUS and/or TEST_USER_OTHER
+ * can exercise situations that only arise when there's more than one uid.
+ */
+typedef enum {
+ /* Whatever user happens to be running the regression test;
+ * such tests also work on Windows */
+ TEST_USER_ME,
+ /* Must be uid 0 on Unix; the test is skipped on Windows */
+ TEST_USER_ROOT,
+ /* The user who would normally run the system bus. This is the DBUS_USER
+ * from configure.ac, usually 'messagebus' but perhaps 'dbus' or
+ * '_dbus'. */
+ TEST_USER_MESSAGEBUS,
+ /* An unprivileged user who is neither root nor DBUS_USER.
+ * This is DBUS_TEST_USER from configure.ac, usually 'nobody'. */
+ TEST_USER_OTHER
+} TestUser;
+
+#define test_assert_no_error(e) _test_assert_no_error (e, __FILE__, __LINE__)
+void _test_assert_no_error (const DBusError *e,
+ const char *file,
+ int line);
+
+gchar *test_get_dbus_daemon (const gchar *config_file,
+ TestUser user,
+ GPid *daemon_pid);
+
+DBusConnection *test_connect_to_bus (TestMainContext *ctx,
+ const gchar *address);
+DBusConnection *test_connect_to_bus_as_user (TestMainContext *ctx,
+ const char *address,
+ TestUser user);
+
+void test_kill_pid (GPid pid);
+
+void test_init (int *argcp, char ***argvp);
+
+void test_progress (char symbol);
+
+#if !GLIB_CHECK_VERSION (2, 38, 0)
+#define g_test_skip(s) my_test_skip (s)
+static inline void my_test_skip (const gchar *s)
+{
+ g_test_message ("SKIP: %s", s);
+}
+#endif
+
+#endif
diff --git a/test/test-utils.c b/test/test-utils.c
index 9a4f3584..cb6cf1fb 100644
--- a/test/test-utils.c
+++ b/test/test-utils.c
@@ -1,13 +1,6 @@
#include <config.h>
#include "test-utils.h"
-#ifndef DBUS_TEST_USE_INTERNAL
-# include <dbus/dbus.h>
-# include <dbus/dbus-glib-lowlevel.h>
-#endif
-
-#ifdef DBUS_TEST_USE_INTERNAL
-
typedef struct
{
DBusLoop *loop;
@@ -104,13 +97,10 @@ cdata_new (DBusLoop *loop,
return cd;
}
-#endif /* DBUS_TEST_USE_INTERNAL */
-
dbus_bool_t
test_connection_setup (TestMainContext *ctx,
DBusConnection *connection)
{
-#ifdef DBUS_TEST_USE_INTERNAL
DBusLoop *loop = ctx;
CData *cd;
@@ -159,12 +149,6 @@ test_connection_setup (TestMainContext *ctx,
dbus_connection_set_timeout_functions (connection, NULL, NULL, NULL, NULL, NULL);
return FALSE;
-#else /* !DBUS_TEST_USE_INTERNAL */
-
- dbus_connection_setup_with_g_main (connection, ctx);
- return TRUE;
-
-#endif /* !DBUS_TEST_USE_INTERNAL */
}
static void
@@ -195,8 +179,6 @@ test_connection_shutdown (TestMainContext *ctx,
dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL);
}
-#ifdef DBUS_TEST_USE_INTERNAL
-
typedef struct
{
DBusLoop *loop;
@@ -278,13 +260,10 @@ remove_server_timeout (DBusTimeout *timeout,
_dbus_loop_remove_timeout (context->loop, timeout);
}
-#endif /* DBUS_TEST_USE_INTERNAL */
-
dbus_bool_t
test_server_setup (TestMainContext *ctx,
DBusServer *server)
{
-#ifdef DBUS_TEST_USE_INTERNAL
DBusLoop *loop = ctx;
ServerData *sd;
@@ -323,13 +302,6 @@ test_server_setup (TestMainContext *ctx,
test_server_shutdown (loop, server);
return FALSE;
-
-#else /* !DBUS_TEST_USE_INTERNAL */
-
- dbus_server_setup_with_g_main (server, ctx);
- return TRUE;
-
-#endif /* !DBUS_TEST_USE_INTERNAL */
}
void
@@ -354,39 +326,32 @@ test_server_shutdown (TestMainContext *ctx,
TestMainContext *
test_main_context_get (void)
{
-#ifdef DBUS_TEST_USE_INTERNAL
return _dbus_loop_new ();
-#else
- /* I suspect dbus-glib relies the default main context in some places */
- return g_main_context_ref (g_main_context_default ());
-#endif
}
TestMainContext *
test_main_context_ref (TestMainContext *ctx)
{
-#ifdef DBUS_TEST_USE_INTERNAL
return _dbus_loop_ref (ctx);
-#else
- return g_main_context_ref (ctx);
-#endif
}
void test_main_context_unref (TestMainContext *ctx)
{
-#ifdef DBUS_TEST_USE_INTERNAL
_dbus_loop_unref (ctx);
-#else
- g_main_context_unref (ctx);
-#endif
}
void test_main_context_iterate (TestMainContext *ctx,
dbus_bool_t may_block)
{
-#ifdef DBUS_TEST_USE_INTERNAL
_dbus_loop_iterate (ctx, may_block);
-#else
- g_main_context_iteration (ctx, may_block);
-#endif
+}
+
+void
+test_pending_call_store_reply (DBusPendingCall *pc,
+ void *data)
+{
+ DBusMessage **message_p = data;
+
+ *message_p = dbus_pending_call_steal_reply (pc);
+ _dbus_assert (*message_p != NULL);
}
diff --git a/test/test-utils.h b/test/test-utils.h
index 0d3f3690..39fae77b 100644
--- a/test/test-utils.h
+++ b/test/test-utils.h
@@ -6,18 +6,9 @@
#include <dbus/dbus.h>
-#ifdef DBUS_TEST_USE_INTERNAL
-
-# include <dbus/dbus-mainloop.h>
-# include <dbus/dbus-internals.h>
- typedef DBusLoop TestMainContext;
-
-#else /* !DBUS_TEST_USE_INTERNAL */
-
-# include <glib.h>
- typedef GMainContext TestMainContext;
-
-#endif /* !DBUS_TEST_USE_INTERNAL */
+#include <dbus/dbus-mainloop.h>
+#include <dbus/dbus-internals.h>
+typedef DBusLoop TestMainContext;
TestMainContext *test_main_context_get (void);
TestMainContext *test_main_context_ref (TestMainContext *ctx);
@@ -34,5 +25,7 @@ dbus_bool_t test_server_setup (TestMainContext *ctx,
DBusServer *server);
void test_server_shutdown (TestMainContext *ctx,
DBusServer *server);
+void test_pending_call_store_reply (DBusPendingCall *pc,
+ void *data);
#endif
diff --git a/test/uid-permissions.c b/test/uid-permissions.c
new file mode 100644
index 00000000..2c62185a
--- /dev/null
+++ b/test/uid-permissions.c
@@ -0,0 +1,199 @@
+/* Integration tests for the dbus-daemon's uid-based hardening
+ *
+ * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
+ * Copyright © 2010-2011 Nokia Corporation
+ * Copyright © 2015 Collabora Ltd.
+ *
+ * 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 AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <config.h>
+
+#include "test-utils-glib.h"
+
+typedef struct {
+ gboolean skip;
+
+ TestMainContext *ctx;
+
+ DBusError e;
+ GError *ge;
+
+ GPid daemon_pid;
+
+ DBusConnection *conn;
+} Fixture;
+
+typedef struct {
+ const char *config_file;
+ TestUser user;
+ gboolean expect_success;
+} Config;
+
+static void
+setup (Fixture *f,
+ gconstpointer context)
+{
+ const Config *config = context;
+ gchar *address;
+
+ f->ctx = test_main_context_get ();
+ f->ge = NULL;
+ dbus_error_init (&f->e);
+
+ address = test_get_dbus_daemon (config ? config->config_file : NULL,
+ TEST_USER_MESSAGEBUS,
+ &f->daemon_pid);
+
+ if (address == NULL)
+ {
+ f->skip = TRUE;
+ return;
+ }
+
+ f->conn = test_connect_to_bus_as_user (f->ctx, address,
+ config ? config->user : TEST_USER_ME);
+
+ if (f->conn == NULL)
+ f->skip = TRUE;
+
+ g_free (address);
+}
+
+static void
+test_uae (Fixture *f,
+ gconstpointer context)
+{
+ const Config *config = context;
+ DBusMessage *m;
+ DBusPendingCall *pc;
+ DBusMessageIter args_iter;
+ DBusMessageIter arr_iter;
+
+ if (f->skip)
+ return;
+
+ m = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "UpdateActivationEnvironment");
+
+ if (m == NULL)
+ g_error ("OOM");
+
+ dbus_message_iter_init_append (m, &args_iter);
+
+ /* Append an empty a{ss} (string => string dictionary). */
+ if (!dbus_message_iter_open_container (&args_iter, DBUS_TYPE_ARRAY,
+ "{ss}", &arr_iter) ||
+ !dbus_message_iter_close_container (&args_iter, &arr_iter))
+ g_error ("OOM");
+
+ if (!dbus_connection_send_with_reply (f->conn, m, &pc,
+ DBUS_TIMEOUT_USE_DEFAULT) ||
+ pc == NULL)
+ g_error ("OOM");
+
+ dbus_message_unref (m);
+ m = NULL;
+
+ if (dbus_pending_call_get_completed (pc))
+ test_pending_call_store_reply (pc, &m);
+ else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply,
+ &m, NULL))
+ g_error ("OOM");
+
+ while (m == NULL)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ if (config->expect_success)
+ {
+ /* it succeeds */
+ g_assert_cmpint (dbus_message_get_type (m), ==,
+ DBUS_MESSAGE_TYPE_METHOD_RETURN);
+ }
+ else
+ {
+ /* it fails, yielding an error message with one string argument */
+ g_assert_cmpint (dbus_message_get_type (m), ==, DBUS_MESSAGE_TYPE_ERROR);
+ g_assert_cmpstr (dbus_message_get_error_name (m), ==,
+ DBUS_ERROR_ACCESS_DENIED);
+ g_assert_cmpstr (dbus_message_get_signature (m), ==, "s");
+ }
+
+ dbus_message_unref (m);
+}
+
+static void
+teardown (Fixture *f,
+ gconstpointer context G_GNUC_UNUSED)
+{
+ dbus_error_free (&f->e);
+ g_clear_error (&f->ge);
+
+ if (f->conn != NULL)
+ {
+ dbus_connection_close (f->conn);
+ dbus_connection_unref (f->conn);
+ f->conn = NULL;
+ }
+
+ if (f->daemon_pid != 0)
+ {
+ test_kill_pid (f->daemon_pid);
+ g_spawn_close_pid (f->daemon_pid);
+ f->daemon_pid = 0;
+ }
+
+ test_main_context_unref (f->ctx);
+}
+
+static Config root_ok_config = {
+ "valid-config-files/multi-user.conf",
+ TEST_USER_ROOT,
+ TRUE
+};
+
+static Config messagebus_ok_config = {
+ "valid-config-files/multi-user.conf",
+ TEST_USER_MESSAGEBUS,
+ TRUE
+};
+
+static Config other_fail_config = {
+ "valid-config-files/multi-user.conf",
+ TEST_USER_OTHER,
+ FALSE
+};
+
+int
+main (int argc,
+ char **argv)
+{
+ test_init (&argc, &argv);
+
+ g_test_add ("/uid-permissions/uae/root", Fixture, &root_ok_config,
+ setup, test_uae, teardown);
+ g_test_add ("/uid-permissions/uae/messagebus", Fixture, &messagebus_ok_config,
+ setup, test_uae, teardown);
+ g_test_add ("/uid-permissions/uae/other", Fixture, &other_fail_config,
+ setup, test_uae, teardown);
+
+ return g_test_run ();
+}
diff --git a/tools/.gitignore b/tools/.gitignore
index d7c21afe..1e0d987a 100644
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -19,3 +19,4 @@ dbus-glib-bindings.h
run-with-tmp-session-bus.conf
print-introspect
dbus-bus-introspect.xml
+dbus-test-tool
diff --git a/tools/GetAllMatchRules.py b/tools/GetAllMatchRules.py
new file mode 100755
index 00000000..6a7e4cd9
--- /dev/null
+++ b/tools/GetAllMatchRules.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python
+
+import sys
+import argparse
+import dbus
+import time
+
+def get_cmdline(pid):
+ cmdline = ''
+ if pid > 0:
+ try:
+ procpath = '/proc/' + str(pid) + '/cmdline'
+ with open(procpath, 'r') as f:
+ cmdline = " ".join(f.readline().split('\0'))
+ except:
+ pass
+ return cmdline
+
+# Parsing parameters
+
+parser = argparse.ArgumentParser(description='Testing D-Bus match rules')
+parser.add_argument('--session', help='session bus', action="store_true")
+parser.add_argument('--system', help='system bus', action="store_true")
+parser.add_argument('--all', help='print all match rules', action="store_true")
+args = parser.parse_args()
+
+if args.system and args.session:
+ parser.print_help()
+ sys.exit(1)
+
+# Fetch data from the bus driver
+
+if args.system:
+ bus = dbus.SystemBus()
+else:
+ bus = dbus.SessionBus()
+
+remote_object = bus.get_object("org.freedesktop.DBus",
+ "/org/freedesktop/DBus")
+bus_iface = dbus.Interface(remote_object, "org.freedesktop.DBus")
+stats_iface = dbus.Interface(remote_object, "org.freedesktop.DBus.Debug.Stats")
+
+try:
+ match_rules = stats_iface.GetAllMatchRules()
+except:
+ print("GetConnectionMatchRules failed: did you enable the Stats interface?")
+ sys.exit(1)
+
+names = bus_iface.ListNames()
+unique_names = [ a for a in names if a.startswith(":") ]
+pids = dict((name, bus_iface.GetConnectionUnixProcessID(name)) for name in unique_names)
+cmds = dict((name, get_cmdline(pids[name])) for name in unique_names)
+well_known_names = [ a for a in names if a not in unique_names ]
+owners = dict((wkn, bus_iface.GetNameOwner(wkn)) for wkn in well_known_names)
+
+rules = dict((k_rules,
+ dict({
+ 'wkn': [k for k, v in owners.items() if v == k_rules],
+ 'pid': pids[k_rules],
+ 'cmd': cmds[k_rules] or "",
+ 'rules': v_rules,
+ 'warnings': dict({
+ 'not_signal': [a for a in v_rules if "type='signal'" not in a],
+ 'no_sender': [a for a in v_rules if "sender=" not in a],
+ 'local': [a for a in v_rules if "org.freedesktop.DBus.Local" in a],
+ 'NameOwnerChanged_arg0': [a for a in v_rules if "member='NameOwnerChanged'" in a and "arg0" not in a]
+ })
+ })
+ ) for k_rules, v_rules in match_rules.items())
+
+warnings = dict({
+ 'not_signal': 'Match rule without selecting signals',
+ 'no_sender': 'Match rule without a sender criteria',
+ 'local': 'Match rule on the org.freedesktop.DBus.Local interface',
+ 'NameOwnerChanged_arg0': 'Match rule on NameOwnerChanged without a arg0* criteria'
+ })
+
+# Print the match rules
+
+# print all match rules without analysing them
+if args.all:
+ for name in rules:
+ print("Connection %s with pid %d '%s' (%s): %d match rules, %d warnings"
+ % (name, rules[name]['pid'], rules[name]['cmd'],
+ ' '.join(rules[name]['wkn']), len(rules[name]['rules']),
+ len(sum(rules[name]['warnings'].values(), []))))
+ for rule in rules[name]['rules']:
+ print("\t%s" % (rule))
+ print("")
+ sys.exit(0)
+
+# analyse match rules and print only the suspicious ones
+for conn,data in rules.items():
+ warnings_count = len(sum(data['warnings'].values(), []))
+ if warnings_count == 0:
+ continue
+
+ print("Connection %s with pid %d '%s' (%s): %d match rules, %d warnings"
+ % (conn, data['pid'], data['cmd'], ' '.join(data['wkn']),
+ len(data['rules']), warnings_count))
+
+ for warn_code,rule_list in [(warn_code,rule_list) \
+ for warn_code, rule_list \
+ in data['warnings'].items() \
+ if len(rule_list) > 0]:
+ print(" - %s:" % (warnings[warn_code]))
+ for rule in rule_list:
+ print(" - %s" % (rule))
+
+ print("")
+
+sys.exit(0)
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 73d95fcf..56a0b7fc 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,5 +1,3 @@
-configdir=$(sysconfdir)/dbus-1
-
AM_CPPFLAGS = \
-I$(top_srcdir) \
$(DBUS_STATIC_BUILD_CPPFLAGS) \
@@ -15,6 +13,8 @@ bin_PROGRAMS = \
dbus-launch \
dbus-monitor \
dbus-send \
+ dbus-test-tool \
+ dbus-update-activation-environment \
$(NULL)
if DBUS_UNIX
@@ -28,12 +28,18 @@ endif
dbus_send_SOURCES= \
dbus-print-message.c \
dbus-print-message.h \
- dbus-send.c
+ dbus-send.c \
+ tool-common.c \
+ tool-common.h \
+ $(NULL)
-dbus_monitor_SOURCES= \
- dbus-monitor.c \
- dbus-print-message.c \
- dbus-print-message.h
+dbus_monitor_SOURCES = \
+ dbus-monitor.c \
+ dbus-print-message.c \
+ dbus-print-message.h \
+ tool-common.c \
+ tool-common.h \
+ $(NULL)
if DBUS_WIN
dbus_launch_SOURCES= \
@@ -43,7 +49,17 @@ else
dbus_launch_SOURCES= \
dbus-launch.c \
dbus-launch-x11.c \
- dbus-launch.h
+ dbus-launch.h \
+ tool-common.c \
+ tool-common.h \
+ $(NULL)
+dbus_launch_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(NULL)
+dbus_launch_LDADD = \
+ $(top_builddir)/dbus/libdbus-1.la \
+ $(DBUS_X_LIBS) \
+ $(NULL)
dbus_run_session_SOURCES = \
dbus-run-session.c
@@ -72,9 +88,27 @@ dbus_uuidgen_LDADD = \
$(top_builddir)/dbus/libdbus-1.la \
$(NULL)
-dbus_launch_LDADD = \
- $(DBUS_X_LIBS) \
+examplesdir = ${docdir}/examples
+dist_examples_SCRIPTS = \
+ GetAllMatchRules.py \
+ $(NULL)
+
+dbus_test_tool_SOURCES = \
+ dbus-echo.c \
+ dbus-spam.c \
+ tool-common.c \
+ tool-common.h \
+ test-tool.c \
+ test-tool.h \
+ $(NULL)
+dbus_test_tool_LDADD = $(top_builddir)/dbus/libdbus-1.la
+
+dbus_update_activation_environment_SOURCES = \
+ dbus-update-activation-environment.c \
+ tool-common.c \
+ tool-common.h \
$(NULL)
+dbus_update_activation_environment_LDADD = $(top_builddir)/dbus/libdbus-1.la
EXTRA_DIST = run-with-tmp-session-bus.sh strtoll.c strtoull.c
CLEANFILES = \
diff --git a/tools/dbus-echo.c b/tools/dbus-echo.c
new file mode 100644
index 00000000..0e7de1bd
--- /dev/null
+++ b/tools/dbus-echo.c
@@ -0,0 +1,246 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* dbus-echo.c - a plain libdbus echo server
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * This program is free software; you can 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.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <dbus/dbus.h>
+
+#include "dbus/dbus-sysdeps.h"
+#include "test-tool.h"
+#include "tool-common.h"
+
+static int sleep_ms = -1;
+static dbus_bool_t noreply = FALSE;
+static dbus_bool_t noread = FALSE;
+
+static void
+usage_echo (int exit_with)
+{
+ fprintf (stderr,
+ "Usage: dbus-test-tool echo [OPTIONS]\n"
+ "\n"
+ "Respond to all method calls with an empty reply.\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ " --name=NAME claim this well-known name first\n"
+ "\n"
+ " --sleep=N sleep N milliseconds before sending each reply\n"
+ "\n"
+ " --session use the session bus (default)\n"
+ " --system use the system bus\n"
+ );
+ exit (exit_with);
+}
+
+static void
+usage_black_hole (int exit_with)
+{
+ fprintf (stderr,
+ "Usage: dbus-test-tool black-hole [OPTIONS]\n"
+ "\n"
+ "Receive method calls but do not reply.\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ " --name=NAME claim this well-known name first\n"
+ "\n"
+ " --no-read don't read anything on the D-Bus socket\n"
+ "\n"
+ " --session use the session bus (default)\n"
+ " --system use the system bus\n"
+ );
+ exit (exit_with);
+}
+
+static DBusHandlerResult
+filter (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ DBusMessage *reply;
+
+ if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (sleep_ms > 0)
+ {
+ _dbus_sleep_milliseconds (sleep_ms);
+ }
+
+ if (!noreply)
+ {
+ reply = dbus_message_new_method_return (message);
+
+ if (reply == NULL)
+ tool_oom ("allocating reply");
+
+ if (!dbus_connection_send (connection, reply, NULL))
+ tool_oom ("sending reply");
+
+ dbus_message_unref (reply);
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusConnection *
+init_connection (DBusBusType type, const char *name)
+{
+ DBusConnection *connection;
+ DBusError error = DBUS_ERROR_INIT;
+
+ connection = dbus_bus_get (type, &error);
+
+ if (connection == NULL)
+ {
+ fprintf (stderr, "Failed to connect to bus: %s: %s\n",
+ error.name, error.message);
+ dbus_error_free (&error);
+ exit (1);
+ }
+
+ if (name != NULL)
+ {
+ if (dbus_bus_request_name (connection, name, DBUS_NAME_FLAG_DO_NOT_QUEUE,
+ NULL) != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+ {
+ fprintf (stderr, "failed to take bus name %s\n", name);
+ exit (1);
+ }
+ }
+ else
+ {
+ printf ("%s\n", dbus_bus_get_unique_name (connection));
+ }
+
+ if (!dbus_connection_add_filter (connection, filter, NULL, NULL))
+ tool_oom ("adding message filter");
+
+ return connection;
+}
+
+int
+dbus_test_tool_echo (int argc, char **argv)
+{
+ DBusConnection *connection;
+ DBusBusType type = DBUS_BUS_SESSION;
+ int i;
+ const char *name = NULL;
+
+ /* argv[1] is the tool name, so start from 2 */
+
+ for (i = 2; i < argc; i++)
+ {
+ const char *arg = argv[i];
+
+ if (strcmp (arg, "--system") == 0)
+ {
+ type = DBUS_BUS_SYSTEM;
+ }
+ else if (strcmp (arg, "--session") == 0)
+ {
+ type = DBUS_BUS_SESSION;
+ }
+ else if (strstr (arg, "--name=") == arg)
+ {
+ name = arg + strlen ("--name=");
+ }
+ else if (strstr (arg, "--sleep-ms=") == arg)
+ {
+ sleep_ms = atoi (arg + strlen ("--sleep-ms="));
+ }
+ else
+ {
+ usage_echo (2);
+ }
+ }
+
+ connection = init_connection (type, name);
+
+ while (dbus_connection_read_write_dispatch (connection, -1))
+ {}
+
+ dbus_connection_unref (connection);
+ return 0;
+}
+
+int
+dbus_test_tool_black_hole (int argc, char **argv)
+{
+ DBusConnection *connection;
+ DBusBusType type = DBUS_BUS_SESSION;
+ int i;
+ const char *name = NULL;
+
+ /* argv[1] is the tool name, so start from 2 */
+
+ for (i = 2; i < argc; i++)
+ {
+ const char *arg = argv[i];
+
+ if (strcmp (arg, "--system") == 0)
+ {
+ type = DBUS_BUS_SYSTEM;
+ }
+ else if (strcmp (arg, "--session") == 0)
+ {
+ type = DBUS_BUS_SESSION;
+ }
+ else if (strstr (arg, "--name=") == arg)
+ {
+ name = arg + strlen ("--name=");
+ }
+ else if (strcmp (arg, "--no-read") == 0)
+ {
+ noread = TRUE;
+ }
+ else
+ {
+ usage_black_hole (2);
+ }
+ }
+
+ connection = init_connection (type, name);
+
+ if (noread)
+ {
+ while (1)
+ _dbus_sleep_milliseconds (3600);
+ }
+
+ noreply = TRUE;
+
+ while (dbus_connection_read_write_dispatch (connection, -1))
+ {}
+
+ dbus_connection_unref (connection);
+ return 0;
+}
diff --git a/tools/dbus-launch-win.c b/tools/dbus-launch-win.c
index d899010a..1dfd0954 100644
--- a/tools/dbus-launch-win.c
+++ b/tools/dbus-launch-win.c
@@ -89,7 +89,7 @@ main (int argc, char **argv)
wchar_t *p;
wchar_t *daemon_name;
int result;
- int showConsole = 0;
+
#ifdef DBUS_WINCE
char *s = NULL;
#else
@@ -102,10 +102,6 @@ main (int argc, char **argv)
BOOL inherit = TRUE;
DWORD flags = 0;
-#ifdef AUTO_ACTIVATE_CONSOLE_WHEN_VERBOSE_MODE
- if (verbose)
- showConsole = 1;
-#endif
GetModuleFileNameW (NULL, dbusDaemonPath, DIM (dbusDaemonPath));
daemon_name = WCSTRINGIFY(DBUS_DAEMON_NAME) L".exe";
diff --git a/tools/dbus-launch.c b/tools/dbus-launch.c
index 41a20e83..0f1e6ede 100644
--- a/tools/dbus-launch.c
+++ b/tools/dbus-launch.c
@@ -38,11 +38,19 @@
#include <sys/select.h>
#include <time.h>
+#include <dbus/dbus.h>
+#include "dbus/dbus-internals.h"
+
#ifdef DBUS_BUILD_X11
#include <X11/Xlib.h>
extern Display *xdisplay;
#endif
+#include "dbus/dbus-internals.h"
+#include "dbus/dbus-sysdeps-unix.h"
+
+#include "tool-common.h"
+
/* PROCESSES
*
* If you are in a shell and run "dbus-launch myapp", here is what happens:
@@ -102,50 +110,25 @@ save_machine_uuid (const char *uuid_arg)
exit (1);
}
- machine_uuid = xstrdup (uuid_arg);
+ machine_uuid = _dbus_strdup (uuid_arg);
}
#ifdef DBUS_BUILD_X11
-#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;
+ machine_uuid = dbus_get_local_machine_id ();
- /* rstrip the read uuid */
- while (len > 31 && isspace((int) uuid[len - 1]))
- len--;
-
- if (len != 32)
- goto out;
+ if (machine_uuid == NULL)
+ return FALSE;
- uuid[len] = '\0';
- machine_uuid = xstrdup (uuid);
verbose ("UID: %s\n", machine_uuid);
- ret = TRUE;
-
-out:
- fclose(f);
- return ret;
+ return TRUE;
}
#endif /* DBUS_BUILD_X11 */
@@ -443,7 +426,8 @@ print_variables (const char *bus_address, pid_t bus_pid, long bus_wid,
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_pid)
+ 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);
@@ -452,7 +436,8 @@ print_variables (const char *bus_address, pid_t bus_pid, long bus_wid,
{
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_pid)
+ 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);
@@ -460,7 +445,8 @@ print_variables (const char *bus_address, pid_t bus_pid, long bus_wid,
else
{
printf ("DBUS_SESSION_BUS_ADDRESS=%s\n", bus_address);
- printf ("DBUS_SESSION_BUS_PID=%ld\n", (long) bus_pid);
+ if (bus_pid)
+ 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);
@@ -854,6 +840,8 @@ main (int argc, char **argv)
int bus_pid_to_babysitter_pipe[2];
int bus_address_to_launcher_pipe[2];
char *config_file;
+ dbus_bool_t user_bus_supported = FALSE;
+ DBusString user_bus;
exit_with_session = FALSE;
config_file = NULL;
@@ -1007,6 +995,7 @@ main (int argc, char **argv)
char *address;
pid_t pid;
long wid;
+ DBusError error = DBUS_ERROR_INIT;
if (get_machine_uuid () == NULL)
{
@@ -1014,6 +1003,37 @@ main (int argc, char **argv)
exit (1);
}
+ if (!_dbus_string_init (&user_bus))
+ tool_oom ("initializing");
+
+ /* If we have an XDG_RUNTIME_DIR and it contains a suitable socket,
+ * dbus-launch --autolaunch can use it, since --autolaunch implies
+ * "I'm OK with getting a bus that is already active".
+ *
+ * (However, plain dbus-launch without --autolaunch must not do so,
+ * because that would break lots of regression tests, which often
+ * use dbus-launch instead of the more appropriate dbus-run-session.)
+ *
+ * At this stage, we just save the user bus's address; later on, the
+ * "babysitter" process will be available to advertise the user-bus
+ * on the X11 display and in ~/.dbus/session-bus, for full
+ * backwards compatibility.
+ */
+ if (!_dbus_lookup_user_bus (&user_bus_supported, &user_bus, &error))
+ {
+ fprintf (stderr, "%s\n", error.message);
+ exit (1);
+ }
+ else if (user_bus_supported)
+ {
+ verbose ("=== Using existing user bus \"%s\"\n",
+ _dbus_string_get_const_data (&user_bus));
+ }
+ else
+ {
+ _dbus_string_free (&user_bus);
+ }
+
verbose ("Autolaunch enabled (using X11).\n");
if (!exit_with_session)
{
@@ -1123,6 +1143,22 @@ main (int argc, char **argv)
close (bus_pid_to_babysitter_pipe[READ_END]);
close (bus_pid_to_babysitter_pipe[WRITE_END]);
+ /* If we have a user bus and want to use it, do so instead of
+ * exec'ing a new dbus-daemon. */
+ if (autolaunch && user_bus_supported)
+ {
+ do_write (bus_pid_to_launcher_pipe[WRITE_END], "0\n", 2);
+ close (bus_pid_to_launcher_pipe[WRITE_END]);
+
+ do_write (bus_address_to_launcher_pipe[WRITE_END],
+ _dbus_string_get_const_data (&user_bus),
+ _dbus_string_get_length (&user_bus));
+ do_write (bus_address_to_launcher_pipe[WRITE_END], "\n", 1);
+ close (bus_address_to_launcher_pipe[WRITE_END]);
+
+ exit (0);
+ }
+
sprintf (write_pid_fd_as_string,
"%d", bus_pid_to_launcher_pipe[WRITE_END]);
diff --git a/tools/dbus-launch.h b/tools/dbus-launch.h
index 8220bb8e..d0ede6ba 100644
--- a/tools/dbus-launch.h
+++ b/tools/dbus-launch.h
@@ -26,6 +26,8 @@
#include <sys/types.h>
+#include <dbus/dbus.h>
+
#ifndef TRUE
#define TRUE (1)
#endif
diff --git a/tools/dbus-monitor.c b/tools/dbus-monitor.c
index 85fd738a..483d42ee 100644
--- a/tools/dbus-monitor.c
+++ b/tools/dbus-monitor.c
@@ -20,6 +20,9 @@
*/
#include <config.h>
+
+#include "dbus/dbus-internals.h" /* just for the macros */
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -34,84 +37,39 @@
#include <time.h>
#include "dbus-print-message.h"
+#include "tool-common.h"
#define EAVESDROPPING_RULE "eavesdrop=true"
-#ifdef DBUS_WIN
-
-/* gettimeofday is not defined on windows */
-#define DBUS_SECONDS_SINCE_1601 11644473600LL
-#define DBUS_USEC_IN_SEC 1000000LL
-
-#ifdef DBUS_WINCE
-
-#ifndef _IOLBF
-#define _IOLBF 0x40
-#endif
-#ifndef _IONBF
-#define _IONBF 0x04
-#endif
-
-void
-GetSystemTimeAsFileTime (LPFILETIME ftp)
-{
- SYSTEMTIME st;
- GetSystemTime (&st);
- SystemTimeToFileTime (&st, ftp);
-}
-#endif
-
-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;
-}
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
#endif
-inline static void
-oom (const char *doing)
-{
- fprintf (stderr, "OOM while %s\n", doing);
- exit (1);
-}
+/* http://www.tcpdump.org/linktypes.html */
+#define LINKTYPE_DBUS 231
static DBusHandlerResult
monitor_filter_func (DBusConnection *connection,
- DBusMessage *message,
- void *user_data)
+ DBusMessage *message,
+ void *user_data)
{
- print_message (message, FALSE);
+ long sec = 0, usec = 0;
+
+ _dbus_get_real_time (&sec, &usec);
+
+ print_message (message, FALSE, sec, usec);
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.
+
+ /* Monitors must not allow libdbus to reply to messages, so we eat
+ * the message. See bug 1719.
*/
return DBUS_HANDLER_RESULT_HANDLED;
}
-#ifdef __APPLE__
-#define PROFILE_TIMED_FORMAT "%s\t%lu\t%d"
-#elif defined(__NetBSD__)
-#include <inttypes.h>
-#define PROFILE_TIMED_FORMAT "%s\t%" PRId64 "\t%d"
-#else
-#define PROFILE_TIMED_FORMAT "%s\t%lu\t%lu"
-#endif
#define TRAP_NULL_STRING(str) ((str) ? (str) : "<none>")
typedef enum
@@ -127,23 +85,30 @@ typedef enum
} ProfileAttributeFlags;
static void
+profile_print_headers (void)
+{
+ printf ("#type\ttimestamp\tserial\tsender\tdestination\tpath\tinterface\tmember\n");
+ printf ("#\t\t\t\t\tin_reply_to\n");
+}
+
+static void
profile_print_with_attrs (const char *type, DBusMessage *message,
- struct timeval *t, ProfileAttributeFlags attrs)
+ long sec, long usec, ProfileAttributeFlags attrs)
{
- printf (PROFILE_TIMED_FORMAT, type, t->tv_sec, t->tv_usec);
+ printf ("%s\t%ld.%06ld", type, sec, 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_REPLY_SERIAL)
+ printf ("\t%u", dbus_message_get_reply_serial (message));
+
if (attrs & PROFILE_ATTRIBUTE_FLAG_PATH)
printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_path (message)));
@@ -162,53 +127,61 @@ profile_print_with_attrs (const char *type, DBusMessage *message,
static void
print_message_profile (DBusMessage *message)
{
- struct timeval t;
+ static dbus_bool_t first = TRUE;
+ long sec = 0, usec = 0;
- if (gettimeofday (&t, NULL) < 0)
+ if (first)
{
- printf ("un\n");
- return;
+ profile_print_headers ();
+ first = FALSE;
}
+ _dbus_get_real_time (&sec, &usec);
+
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;
+ profile_print_with_attrs ("mc", message, sec, usec,
+ PROFILE_ATTRIBUTE_FLAG_SERIAL |
+ PROFILE_ATTRIBUTE_FLAG_SENDER |
+ PROFILE_ATTRIBUTE_FLAG_DESTINATION |
+ 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;
+ profile_print_with_attrs ("mr", message, sec, usec,
+ PROFILE_ATTRIBUTE_FLAG_SERIAL |
+ PROFILE_ATTRIBUTE_FLAG_SENDER |
+ 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;
+ profile_print_with_attrs ("err", message, sec, usec,
+ PROFILE_ATTRIBUTE_FLAG_SERIAL |
+ PROFILE_ATTRIBUTE_FLAG_SENDER |
+ 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;
+ profile_print_with_attrs ("sig", message, sec, usec,
+ PROFILE_ATTRIBUTE_FLAG_SERIAL |
+ PROFILE_ATTRIBUTE_FLAG_SENDER |
+ PROFILE_ATTRIBUTE_FLAG_DESTINATION |
+ 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;
+ printf ("%s\t%ld.%06ld", "tun", sec, usec);
+ break;
}
}
static DBusHandlerResult
-profile_filter_func (DBusConnection *connection,
- DBusMessage *message,
- void *user_data)
+profile_filter_func (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
{
print_message_profile (message);
@@ -220,10 +193,79 @@ profile_filter_func (DBusConnection *connection,
return DBUS_HANDLER_RESULT_HANDLED;
}
+typedef enum {
+ BINARY_MODE_NOT,
+ BINARY_MODE_RAW,
+ BINARY_MODE_PCAP
+} BinaryMode;
+
+static DBusHandlerResult
+binary_filter_func (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ BinaryMode mode = _DBUS_POINTER_TO_INT (user_data);
+ char *blob;
+ int len;
+
+ /* It would be nice if we could do a zero-copy "peek" one day, but libdbus
+ * is so copy-happy that this isn't really a big deal.
+ */
+ if (!dbus_message_marshal (message, &blob, &len))
+ tool_oom ("retrieving message");
+
+ switch (mode)
+ {
+ case BINARY_MODE_PCAP:
+ {
+ long tv_sec, tv_usec;
+ /* seconds, microseconds, bytes captured (possibly truncated),
+ * original length.
+ * http://wiki.wireshark.org/Development/LibpcapFileFormat
+ */
+ dbus_uint32_t header[4] = { 0, 0, len, len };
+
+ /* If this gets padded then we'd need to write it out in pieces */
+ _DBUS_STATIC_ASSERT (sizeof (header) == 16);
+
+ _dbus_get_real_time (&tv_sec, &tv_usec);
+ header[0] = tv_sec;
+ header[1] = tv_usec;
+
+ if (!tool_write_all (STDOUT_FILENO, header, sizeof (header)))
+ {
+ perror ("dbus-monitor: write");
+ exit (1);
+ }
+ }
+ break;
+
+ case BINARY_MODE_RAW:
+ default:
+ /* nothing special, just the raw message stream */
+ break;
+ }
+
+ if (!tool_write_all (STDOUT_FILENO, blob, len))
+ {
+ perror ("dbus-monitor: write");
+ exit (1);
+ }
+
+ dbus_free (blob);
+
+ 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);
+ fprintf (stderr, "Usage: %s [--system | --session | --address ADDRESS] [--monitor | --profile | --pcap | --binary ] [watch expressions]\n", name);
exit (ecode);
}
@@ -242,6 +284,66 @@ only_one_type (dbus_bool_t *seen_bus_type,
}
}
+static dbus_bool_t
+become_monitor (DBusConnection *connection,
+ int numFilters,
+ const char * const *filters)
+{
+ DBusError error = DBUS_ERROR_INIT;
+ DBusMessage *m;
+ DBusMessage *r;
+ int i;
+ dbus_uint32_t zero = 0;
+ DBusMessageIter appender, array_appender;
+
+ m = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS, DBUS_INTERFACE_MONITORING, "BecomeMonitor");
+
+ if (m == NULL)
+ tool_oom ("becoming a monitor");
+
+ dbus_message_iter_init_append (m, &appender);
+
+ if (!dbus_message_iter_open_container (&appender, DBUS_TYPE_ARRAY, "s",
+ &array_appender))
+ tool_oom ("opening string array");
+
+ for (i = 0; i < numFilters; i++)
+ {
+ if (!dbus_message_iter_append_basic (&array_appender, DBUS_TYPE_STRING,
+ &filters[i]))
+ tool_oom ("adding filter to array");
+ }
+
+ if (!dbus_message_iter_close_container (&appender, &array_appender) ||
+ !dbus_message_iter_append_basic (&appender, DBUS_TYPE_UINT32, &zero))
+ tool_oom ("finishing arguments");
+
+ r = dbus_connection_send_with_reply_and_block (connection, m, -1, &error);
+
+ if (r != NULL)
+ {
+ dbus_message_unref (r);
+ }
+ else if (dbus_error_has_name (&error, DBUS_ERROR_UNKNOWN_INTERFACE))
+ {
+ fprintf (stderr, "dbus-monitor: unable to enable new-style monitoring, "
+ "your dbus-daemon is too old. Falling back to eavesdropping.\n");
+ dbus_error_free (&error);
+ }
+ else
+ {
+ fprintf (stderr, "dbus-monitor: unable to enable new-style monitoring: "
+ "%s: \"%s\". Falling back to eavesdropping.\n",
+ error.name, error.message);
+ dbus_error_free (&error);
+ }
+
+ dbus_message_unref (m);
+
+ return (r != NULL);
+}
+
int
main (int argc, char *argv[])
{
@@ -251,7 +353,7 @@ main (int argc, char *argv[])
DBusHandleMessageFunction filter_func = monitor_filter_func;
char *address = NULL;
dbus_bool_t seen_bus_type = FALSE;
-
+ BinaryMode binary_mode = BINARY_MODE_NOT;
int i = 0, j = 0, numFilters = 0;
char **filters = NULL;
@@ -293,15 +395,31 @@ main (int argc, char *argv[])
usage (argv[0], 1);
}
else if (!strcmp (arg, "--help"))
- usage (argv[0], 0);
+ usage (argv[0], 0);
else if (!strcmp (arg, "--monitor"))
- filter_func = monitor_filter_func;
+ {
+ filter_func = monitor_filter_func;
+ binary_mode = BINARY_MODE_NOT;
+ }
else if (!strcmp (arg, "--profile"))
- filter_func = profile_filter_func;
+ {
+ filter_func = profile_filter_func;
+ binary_mode = BINARY_MODE_NOT;
+ }
+ else if (!strcmp (arg, "--binary"))
+ {
+ filter_func = binary_filter_func;
+ binary_mode = BINARY_MODE_RAW;
+ }
+ else if (!strcmp (arg, "--pcap"))
+ {
+ filter_func = binary_filter_func;
+ binary_mode = BINARY_MODE_PCAP;
+ }
else if (!strcmp (arg, "--"))
- continue;
+ continue;
else if (arg[0] == '-')
- usage (argv[0], 1);
+ usage (argv[0], 1);
else {
unsigned int filter_len;
numFilters++;
@@ -312,10 +430,10 @@ main (int argc, char *argv[])
filters = (char **) realloc (filters, numFilters * sizeof (char *));
if (filters == NULL)
- oom ("adding a new filter slot");
+ tool_oom ("adding a new filter slot");
filters[j] = (char *) malloc (filter_len);
if (filters[j] == NULL)
- oom ("adding a new filter");
+ tool_oom ("adding a new filter");
snprintf (filters[j], filter_len, "%s,%s", EAVESDROPPING_RULE, arg);
j++;
}
@@ -329,12 +447,12 @@ main (int argc, char *argv[])
if (connection)
{
if (!dbus_bus_register (connection, &error))
- {
+ {
fprintf (stderr, "Failed to register connection to bus at %s: %s\n",
- address, error.message);
+ address, error.message);
dbus_error_free (&error);
exit (1);
- }
+ }
}
}
else
@@ -370,7 +488,19 @@ main (int argc, char *argv[])
* a monitor */
dbus_connection_set_route_peer_messages (connection, TRUE);
- if (numFilters)
+ if (!dbus_connection_add_filter (connection, filter_func,
+ _DBUS_INT_TO_POINTER (binary_mode), NULL))
+ {
+ fprintf (stderr, "Couldn't add filter!\n");
+ exit (1);
+ }
+
+ if (become_monitor (connection, numFilters,
+ (const char * const *) filters))
+ {
+ /* no more preparation needed */
+ }
+ else if (numFilters)
{
size_t offset = 0;
for (i = 0; i < j; i++)
@@ -387,7 +517,7 @@ main (int argc, char *argv[])
dbus_bus_add_match (connection, filters[i] + offset, &error);
}
- if (dbus_error_is_set (&error))
+ if (dbus_error_is_set (&error))
{
fprintf (stderr, "Failed to setup match \"%s\": %s\n",
filters[i], error.message);
@@ -413,10 +543,45 @@ main (int argc, char *argv[])
}
}
- if (!dbus_connection_add_filter (connection, filter_func, NULL, NULL)) {
- fprintf (stderr, "Couldn't add filter!\n");
- exit (1);
- }
+ switch (binary_mode)
+ {
+ case BINARY_MODE_NOT:
+ case BINARY_MODE_RAW:
+ break;
+
+ case BINARY_MODE_PCAP:
+ {
+ /* We're not using libpcap because the file format is simple
+ * enough not to need it.
+ * http://wiki.wireshark.org/Development/LibpcapFileFormat */
+ struct {
+ dbus_uint32_t magic;
+ dbus_uint16_t major_version;
+ dbus_uint16_t minor_version;
+ dbus_int32_t timezone;
+ dbus_uint32_t precision;
+ dbus_uint32_t max_length;
+ dbus_uint32_t link_type;
+ } header = {
+ 0xA1B2C3D4U, /* magic number */
+ 2, 4, /* v2.4 */
+ 0, /* capture in GMT */
+ 0, /* no opinion on timestamp precision */
+ (1 << 27), /* D-Bus spec says so */
+ LINKTYPE_DBUS
+ };
+
+ /* Assert that there is no padding */
+ _DBUS_STATIC_ASSERT (sizeof (header) == 24);
+
+ if (!tool_write_all (STDOUT_FILENO, &header, sizeof (header)))
+ {
+ perror ("dbus-monitor: write");
+ exit (1);
+ }
+ }
+ break;
+ }
while (dbus_connection_read_write_dispatch(connection, -1))
;
diff --git a/tools/dbus-print-message.c b/tools/dbus-print-message.c
index e0dd2da6..80c96986 100644
--- a/tools/dbus-print-message.c
+++ b/tools/dbus-print-message.c
@@ -23,9 +23,22 @@
#include <config.h>
#include "dbus-print-message.h"
+#ifdef DBUS_UNIX
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#endif
+
#include <stdlib.h>
#include "config.h"
+#include "tool-common.h"
+
static const char*
type_to_name (int message_type)
{
@@ -54,7 +67,9 @@ indent (int depth)
}
static void
-print_hex (unsigned char *bytes, unsigned int len, int depth)
+print_hex (const unsigned char *bytes,
+ unsigned int len,
+ int depth)
{
unsigned int i, columns;
@@ -99,48 +114,189 @@ print_hex (unsigned char *bytes, unsigned int len, int depth)
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;
+ /* True if every byte in the bytestring (so far) is printable
+ * ASCII, with one exception: the last byte is also allowed to be \0. */
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++;
+ const unsigned char *bytes;
+ int len;
+ int i;
- if (val < 32 || val > 126)
- all_ascii = FALSE;
+ dbus_message_iter_get_fixed_array (iter, &bytes, &len);
- if (len == max)
+ for (i = 0; i < len; i++)
+ {
+ if ((bytes[i] < 32 || bytes[i] > 126) &&
+ (i < len - 1 || bytes[i] != '\0'))
{
- max *= 2;
- bytes = realloc (bytes, max + 1);
+ all_ascii = FALSE;
+ break;
}
-
- dbus_message_iter_next (iter);
}
- if (all_ascii)
+ if (all_ascii && len > 0 && bytes[len - 1] == '\0')
{
- bytes[len] = '\0';
- printf ("array of bytes \"%s\"\n", bytes);
+ printf ("array of bytes \"%s\" + \\0\n", bytes);
+ }
+ else if (all_ascii)
+ {
+ unsigned char *copy = dbus_malloc (len + 1);
+
+ if (copy == NULL)
+ tool_oom ("copying bytestring");
+
+ memcpy (copy, bytes, len);
+ copy[len] = '\0';
+ printf ("array of bytes \"%s\"\n", copy);
+ dbus_free (copy);
}
else
{
print_hex (bytes, len, depth);
}
+}
- free (bytes);
+#ifdef DBUS_UNIX
+static void
+print_fd (int fd, int depth)
+{
+ int ret;
+ struct stat statbuf = {0,};
+ union {
+ struct sockaddr sa;
+ struct sockaddr_storage storage;
+ struct sockaddr_un un;
+ struct sockaddr_in ipv4;
+ struct sockaddr_in6 ipv6;
+ } addr, peer;
+ char hostip[INET6_ADDRSTRLEN];
+ int addrlen = sizeof (addr);
+ int peerlen = sizeof (peer);
+ int has_peer;
+
+ /* Don't print the fd number: it is different in every process and since
+ * dbus-monitor closes the fd after reading it, the same number would be
+ * printed again and again.
+ */
+ printf ("file descriptor\n");
+ if (fd == -1)
+ return;
+
+ ret = fstat (fd, &statbuf);
+ if (ret == -1)
+ return;
+
+ indent (depth+1);
+ printf ("inode: %d\n", (int) statbuf.st_ino);
+
+ indent (depth+1);
+ printf ("type: ");
+ if (S_ISREG(statbuf.st_mode))
+ printf ("file\n");
+ if (S_ISDIR(statbuf.st_mode))
+ printf ("directory\n");
+ if (S_ISCHR(statbuf.st_mode))
+ printf ("char\n");
+ if (S_ISBLK(statbuf.st_mode))
+ printf ("block\n");
+ if (S_ISFIFO(statbuf.st_mode))
+ printf ("fifo\n");
+ if (S_ISLNK(statbuf.st_mode))
+ printf ("link\n");
+ if (S_ISSOCK(statbuf.st_mode))
+ printf ("socket\n");
+
+ /* If it's not a socket, getsockname will just return -1 with errno
+ * ENOTSOCK. */
+
+ memset (&addr, 0, sizeof (addr));
+ memset (&peer, 0, sizeof (peer));
+
+ if (getsockname(fd, &addr.sa, &addrlen))
+ return;
+
+ has_peer = !getpeername(fd, &peer.sa, &peerlen);
+
+ indent (depth+1);
+ printf ("address family: ");
+ switch (addr.sa.sa_family)
+ {
+ case AF_UNIX:
+ printf("unix\n");
+ if (addr.un.sun_path[0] == '\0')
+ {
+ /* Abstract socket might not be zero-terminated and length is
+ * variable. Who designed this interface?
+ * Write the name in the same way as /proc/net/unix
+ * See manual page unix(7)
+ */
+ indent (depth+1);
+ printf ("name @%.*s\n",
+ (int) (addrlen - sizeof (sa_family_t) - 1),
+ &(addr.un.sun_path[1]));
+
+ if (has_peer)
+ {
+ indent (depth+1);
+ printf ("peer @%.*s\n",
+ (int) (addrlen - sizeof (sa_family_t) - 1),
+ &(addr.un.sun_path[1]));
+ }
+ }
+ else
+ {
+ indent (depth+1);
+ printf ("name %s\n", addr.un.sun_path);
+ if (has_peer)
+ {
+ indent (depth+1);
+ printf ("peer %s\n", peer.un.sun_path);
+ }
+ }
+ break;
+
+ case AF_INET:
+ printf ("inet\n");
+ if (inet_ntop (AF_INET, &addr.ipv4.sin_addr, hostip, sizeof (hostip)))
+ {
+ indent (depth+1);
+ printf ("name %s port %u\n", hostip, ntohs (addr.ipv4.sin_port));
+ }
+ if (has_peer && inet_ntop (AF_INET, &peer.ipv4.sin_addr, hostip, sizeof (hostip)))
+ {
+ indent (depth+1);
+ printf ("peer %s port %u\n", hostip, ntohs (peer.ipv4.sin_port));
+ }
+
+ break;
+
+#ifdef AF_INET6
+ case AF_INET6:
+ printf ("inet6\n");
+ if (inet_ntop (AF_INET6, &addr.ipv6.sin6_addr, hostip, sizeof (hostip)))
+ {
+ indent (depth+1);
+ printf ("name %s port %u\n", hostip, ntohs (addr.ipv6.sin6_port));
+ }
+ if (has_peer && inet_ntop (AF_INET6, &peer.ipv6.sin6_addr, hostip, sizeof (hostip)))
+ {
+ indent (depth+1);
+ printf ("peer %s port %u\n", hostip, ntohs (peer.ipv6.sin6_port));
+ }
+ break;
+#endif
+
+#ifdef AF_BLUETOOTH
+ case AF_BLUETOOTH:
+ printf ("bluetooth\n");
+ break;
+#endif
+
+ default:
+ printf ("unknown (%d)\n", addr.sa.sa_family);
+ break;
+ }
}
+#endif
static void
print_iter (DBusMessageIter *iter, dbus_bool_t literal, int depth)
@@ -150,220 +306,230 @@ print_iter (DBusMessageIter *iter, dbus_bool_t literal, int depth)
int type = dbus_message_iter_get_arg_type (iter);
if (type == DBUS_TYPE_INVALID)
- break;
+ 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);
+ {
+ 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;
- }
+ break;
+ }
- case DBUS_TYPE_UINT64:
- {
- dbus_uint64_t val;
- dbus_message_iter_get_basic (iter, &val);
+ 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;
- }
-
- case DBUS_TYPE_UNIX_FD:
- {
- int fd;
- dbus_message_iter_get_basic (iter, &fd);
- printf ("unix fd %d\n", fd);
- break;
- }
-
- default:
- printf (" (dbus-monitor too dumb to decipher arg type '%c')\n", type);
- break;
- }
+ 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;
+ }
+
+#ifdef DBUS_UNIX
+ case DBUS_TYPE_UNIX_FD:
+ {
+ int fd;
+ dbus_message_iter_get_basic (iter, &fd);
+
+ print_fd (fd, depth+1);
+
+ /* dbus_message_iter_get_basic() duplicated the fd, we need to
+ * close it after use. The original fd will be closed when the
+ * DBusMessage is released.
+ */
+ close (fd);
+
+ break;
+ }
+#endif
+
+ 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)
+print_message (DBusMessage *message, dbus_bool_t literal, long sec, long usec)
{
DBusMessageIter iter;
const char *sender;
@@ -376,37 +542,48 @@ print_message (DBusMessage *message, dbus_bool_t literal)
if (!literal)
{
- printf ("%s sender=%s -> dest=%s",
- type_to_name (message_type),
- sender ? sender : "(null sender)",
- destination ? destination : "(null destination)");
-
+ if (sec != 0 || usec != 0)
+ {
+ printf ("%s time=%ld.%06ld sender=%s -> destination=%s",
+ type_to_name (message_type), sec, usec,
+ sender ? sender : "(null sender)",
+ destination ? destination : "(null destination)");
+ }
+ else
+ {
+ printf ("%s sender=%s -> destination=%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",
+ {
+ 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;
+ 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",
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ printf (" serial=%u reply_serial=%u\n",
+ dbus_message_get_serial (message),
dbus_message_get_reply_serial (message));
- break;
+ break;
- case DBUS_MESSAGE_TYPE_ERROR:
- printf (" error_name=%s reply_serial=%u\n",
- dbus_message_get_error_name (message),
+ 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;
+ break;
- default:
- printf ("\n");
- break;
- }
+ default:
+ printf ("\n");
+ break;
+ }
}
dbus_message_iter_init (message, &iter);
diff --git a/tools/dbus-print-message.h b/tools/dbus-print-message.h
index 26700d84..d45bc79d 100644
--- a/tools/dbus-print-message.h
+++ b/tools/dbus-print-message.h
@@ -26,6 +26,6 @@
#include <string.h>
#include <dbus/dbus.h>
-void print_message (DBusMessage *message, dbus_bool_t literal);
+void print_message (DBusMessage *message, dbus_bool_t literal, long sec, long usec);
#endif /* DBUS_PRINT_MESSAGE_H */
diff --git a/tools/dbus-send.c b/tools/dbus-send.c
index d3ff2589..0dc1f5b3 100644
--- a/tools/dbus-send.c
+++ b/tools/dbus-send.c
@@ -25,6 +25,7 @@
#include <string.h>
#include <dbus/dbus.h>
+#include "dbus/dbus-internals.h"
#ifndef HAVE_STRTOLL
#undef strtoll
@@ -229,8 +230,8 @@ main (int argc, char *argv[])
DBusConnection *connection;
DBusError error;
DBusMessage *message;
- int print_reply;
- int print_reply_literal;
+ dbus_bool_t print_reply;
+ dbus_bool_t print_reply_literal;
int reply_timeout;
DBusMessageIter iter;
int i;
@@ -573,7 +574,10 @@ main (int argc, char *argv[])
if (reply)
{
- print_message (reply, print_reply_literal);
+ long sec, usec;
+
+ _dbus_get_real_time (&sec, &usec);
+ print_message (reply, print_reply_literal, sec, usec);
dbus_message_unref (reply);
}
}
diff --git a/tools/dbus-spam.c b/tools/dbus-spam.c
new file mode 100644
index 00000000..c78d8ea6
--- /dev/null
+++ b/tools/dbus-spam.c
@@ -0,0 +1,524 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* dbus-spam.c - a plain libdbus message-sender, loosely based on dbus-send
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * This program is free software; you can 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.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <dbus/dbus.h>
+
+#include "test-tool.h"
+#include "tool-common.h"
+
+static dbus_bool_t ignore_errors = FALSE;
+
+static void
+usage (int ecode)
+{
+ fprintf (stderr,
+ "Usage: dbus-test-tool spam [OPTIONS]\n"
+ "\n"
+ "Repeatedly call com.example.Spam() on the given D-Bus service.\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ " --session use the session bus (default)\n"
+ " --system use the system bus\n"
+ "\n"
+ " --ignore-errors ignore errors\n"
+ " --dest=NAME call methods on NAME (default " DBUS_SERVICE_DBUS ")\n"
+ "\n"
+ " --count=N send N messages (default 1)\n"
+ " --queue=N queue up N messages at a time (default 1)\n"
+ " --flood send all messages immediately\n"
+ " --no-reply set the NO_REPLY flag (implies --flood)\n"
+ " --messages-per-conn=N after sending messages-per-conn, wait\n"
+ " for the pending replies if any, then reconnect\n"
+ " (default: don't reconnect)\n"
+ "\n"
+ " --string send payload as a string (default)\n"
+ " --bytes send payload as a byte-array\n"
+ " --empty send an empty payload\n"
+ "\n"
+ " --payload=S use S as payload (default \"hello, world!\")\n"
+ " --stdin read payload from stdin, until EOF\n"
+ " --message-stdin read a complete D-Bus message from stdin\n"
+ " --random-size read whitespace-separated ASCII decimal\n"
+ " payload sizes from stdin and pick one randomly\n"
+ " for each message\n"
+ "\n"
+ " --seed=SEED seed for srand (default is time())\n"
+ "\n"
+ );
+ exit (ecode);
+}
+
+static void
+pc_notify (DBusPendingCall *pc,
+ void *data)
+{
+ DBusMessage *message;
+ int *received_p = data;
+ DBusError error;
+
+ dbus_error_init (&error);
+
+ message = dbus_pending_call_steal_reply (pc);
+
+ if (!ignore_errors && dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR)
+ {
+ dbus_set_error_from_message (&error, message);
+ fprintf (stderr, "Failed to receive reply #%d: %s: %s\n", *received_p,
+ error.name, error.message);
+ }
+ else
+ {
+ VERBOSE (stderr, "received message #%d\n", *received_p);
+ }
+
+ (*received_p)++;
+}
+
+static void
+consume_stdin (char **payload_p,
+ size_t *len_p)
+{
+ const size_t BLOCK_SIZE = 4096;
+ size_t len = BLOCK_SIZE;
+ size_t pos = 0;
+ size_t n;
+ char *buf;
+
+ buf = dbus_malloc (len);
+
+ if (buf == NULL)
+ tool_oom ("reading payload from stdin");
+
+ while (1)
+ {
+ if (len - pos < BLOCK_SIZE)
+ {
+ char *tmp = dbus_realloc (buf, len + BLOCK_SIZE);
+
+ if (tmp == NULL)
+ tool_oom ("reading payload from stdin");
+
+ buf = tmp;
+ len += BLOCK_SIZE;
+ }
+
+ n = fread (buf + pos, 1, len - pos, stdin);
+
+ if (n <= 0)
+ {
+ /* EOF or error - treat as EOF */
+ break;
+ }
+
+ pos += n;
+ }
+
+ *len_p = pos;
+ *payload_p = buf;
+}
+
+int
+dbus_test_tool_spam (int argc, char **argv)
+{
+ DBusConnection *connection = NULL;
+ DBusError error = DBUS_ERROR_INIT;
+ DBusBusType type = DBUS_BUS_SESSION;
+ const char *destination = DBUS_SERVICE_DBUS;
+ int i;
+ int count = 1;
+ int sent = 0;
+ unsigned int sent_in_this_conn = 0;
+ int received = 0;
+ unsigned int received_before_this_conn = 0;
+ int queue_len = 1;
+ const char *payload = NULL;
+ char *payload_buf = NULL;
+ size_t payload_len;
+ int payload_type = DBUS_TYPE_STRING;
+ DBusMessage *template = NULL;
+ dbus_bool_t flood = FALSE;
+ dbus_bool_t no_reply = FALSE;
+ unsigned int messages_per_conn = 0;
+ unsigned int seed = time (NULL);
+ int n_random_sizes = 0;
+ unsigned int *random_sizes = NULL;
+
+ /* argv[1] is the tool name, so start from 2 */
+
+ for (i = 2; i < argc; i++)
+ {
+ const char *arg = argv[i];
+
+ if (strcmp (arg, "--system") == 0)
+ {
+ type = DBUS_BUS_SYSTEM;
+ }
+ else if (strcmp (arg, "--session") == 0)
+ {
+ type = DBUS_BUS_SESSION;
+ }
+ else if (strstr (arg, "--count=") == arg)
+ {
+ count = atoi (arg + strlen ("--count="));
+
+ if (count < 1)
+ usage (2);
+ }
+ else if (strcmp (arg, "--ignore-errors") == 0)
+ {
+ ignore_errors = TRUE;
+ }
+ else if (strstr (arg, "--dest=") == arg)
+ {
+ destination = arg + strlen ("--dest=");
+ }
+ else if (strstr (arg, "--payload=") == arg)
+ {
+ payload = arg + strlen ("--payload=");
+ }
+ else if (strcmp (arg, "--stdin") == 0)
+ {
+ consume_stdin (&payload_buf, &payload_len);
+ payload = payload_buf;
+ }
+ else if (strcmp (arg, "--message-stdin") == 0)
+ {
+ consume_stdin (&payload_buf, &payload_len);
+ payload = payload_buf;
+ template = dbus_message_demarshal (payload, payload_len, &error);
+
+ if (template == NULL)
+ {
+ fprintf (stderr, "Unable to demarshal template message: %s: %s",
+ error.name, error.message);
+ exit (1);
+ }
+
+ if (dbus_message_get_type (template) != DBUS_MESSAGE_TYPE_METHOD_CALL)
+ {
+ fprintf (stderr, "Template message must be a method call\n");
+ exit (1);
+ }
+ }
+ else if (strcmp (arg, "--random-size") == 0)
+ {
+ unsigned int len, max = 0;
+ int j, consumed = 0;
+ const char *p;
+
+ consume_stdin (&payload_buf, &payload_len);
+
+ for (p = payload_buf; p < payload_buf + payload_len; p += consumed)
+ {
+ /* the space character matches any (or no) whitespace */
+ if (sscanf (p, " %u %n", &len, &consumed) == 0)
+ break;
+
+ n_random_sizes++;
+ }
+
+ random_sizes = dbus_new0 (int, n_random_sizes);
+
+ if (random_sizes == NULL)
+ tool_oom ("allocating array of message lengths");
+
+ for (p = payload_buf, j = 0;
+ p < payload_buf + payload_len && j < n_random_sizes;
+ p += consumed, j++)
+ {
+ sscanf (p, " %u %n", &len, &consumed);
+ random_sizes[j] = len;
+
+ if (len > max)
+ max = len;
+ }
+
+ dbus_free (payload_buf);
+ payload_len = max + 1;
+ payload_buf = dbus_new (char, payload_len);
+ payload = payload_buf;
+
+ if (payload_buf == NULL)
+ tool_oom ("allocating maximum-sized payload");
+
+ memset (payload_buf, 'X', payload_len);
+ payload_buf[payload_len - 1] = '\0';
+ }
+ else if (strcmp (arg, "--empty") == 0)
+ {
+ payload_type = DBUS_TYPE_INVALID;
+ }
+ else if (strcmp (arg, "--string") == 0)
+ {
+ payload_type = DBUS_TYPE_STRING;
+ }
+ else if (strcmp (arg, "--bytes") == 0)
+ {
+ payload_type = DBUS_TYPE_ARRAY;
+ }
+ else if (strcmp (arg, "--flood") == 0)
+ {
+ if (queue_len > 1)
+ usage (2);
+
+ if (messages_per_conn > 0)
+ usage (2);
+
+ flood = TRUE;
+ queue_len = -1;
+ }
+ else if (strcmp (arg, "--no-reply") == 0)
+ {
+ if (queue_len > 1)
+ usage (2);
+
+ queue_len = -1;
+ no_reply = TRUE;
+ }
+ else if (strstr (arg, "--queue=") == arg)
+ {
+ if (flood || no_reply)
+ usage (2);
+
+ queue_len = atoi (arg + strlen ("--queue="));
+
+ if (queue_len < 1)
+ usage (2);
+ }
+ else if (strstr (arg, "--seed=") == arg)
+ {
+ seed = strtoul (arg + strlen ("--seed="), NULL, 10);
+ }
+ else if (strstr (arg, "--messages-per-conn=") == arg)
+ {
+ messages_per_conn = atoi (arg + strlen ("--messages-per-conn="));
+
+ if (messages_per_conn > 0 && flood)
+ usage (2);
+ }
+ else
+ {
+ usage (2);
+ }
+ }
+
+ srand (seed);
+
+ if (payload == NULL)
+ {
+ payload = "hello, world!";
+ payload_len = strlen (payload);
+ }
+
+ VERBOSE (stderr, "Will send up to %d messages, with up to %d queued, max %d per connection\n",
+ count, queue_len, messages_per_conn);
+
+ while (no_reply ? sent < count : received < count)
+ {
+ /* Connect?
+ * - In the first iteration
+ * or
+ * - When messages_per_conn messages have been sent and no replies are being waited for
+ */
+ if (connection == NULL ||
+ (messages_per_conn > 0 && sent_in_this_conn == messages_per_conn &&
+ (no_reply || received - received_before_this_conn == messages_per_conn)))
+ {
+ if (connection != NULL)
+ {
+ dbus_connection_flush (connection);
+ dbus_connection_close (connection);
+ dbus_connection_unref (connection);
+ }
+
+ VERBOSE (stderr, "New connection.\n");
+ connection = dbus_bus_get_private (type, &error);
+
+ if (connection == NULL)
+ {
+ fprintf (stderr, "Failed to connect to bus: %s: %s\n",
+ error.name, error.message);
+ dbus_error_free (&error);
+ dbus_free (random_sizes);
+ dbus_free (payload_buf);
+ return 1;
+ }
+
+ sent_in_this_conn = 0;
+ received_before_this_conn = received;
+ }
+
+ /* Send another message? Only if we don't exceed the 3 limits:
+ * - total amount of messages
+ * - messages sent on this connection
+ * - queue
+ */
+ while (sent < count &&
+ (messages_per_conn == 0 || sent_in_this_conn < messages_per_conn) &&
+ (queue_len == -1 || sent_in_this_conn < queue_len + received - received_before_this_conn))
+ {
+ DBusMessage *message;
+
+ if (template != NULL)
+ {
+ message = dbus_message_copy (template);
+
+ if (message == NULL)
+ tool_oom ("copying message");
+
+ dbus_message_set_no_reply (message, no_reply);
+ }
+ else
+ {
+ dbus_bool_t mem;
+ unsigned int len = 0;
+
+ message = dbus_message_new_method_call (destination,
+ "/",
+ "com.example",
+ "Spam");
+
+ if (message == NULL)
+ tool_oom ("allocating message");
+
+ dbus_message_set_no_reply (message, no_reply);
+
+ switch (payload_type)
+ {
+ case DBUS_TYPE_STRING:
+ if (random_sizes != NULL)
+ {
+ /* this isn't fair, strictly speaking - the first few
+ * are a bit more likely to be chosen, unless
+ * RAND_MAX is divisible by n_random_sizes - but it's
+ * good enough for traffic-generation */
+ len = random_sizes[rand () % n_random_sizes];
+ payload_buf[len] = '\0';
+ }
+
+ mem = dbus_message_append_args (message,
+ DBUS_TYPE_STRING, &payload,
+ DBUS_TYPE_INVALID);
+
+ if (random_sizes != NULL)
+ {
+ /* undo the truncation above */
+ payload_buf[len] = 'X';
+ }
+
+ break;
+
+ case DBUS_TYPE_ARRAY:
+ len = payload_len;
+
+ /* as above, not strictly fair, but close enough */
+ if (random_sizes != NULL)
+ len = random_sizes[rand () % n_random_sizes];
+
+ mem = dbus_message_append_args (message,
+ DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE,
+ &payload,
+ (dbus_uint32_t) len,
+ DBUS_TYPE_INVALID);
+ break;
+
+ default:
+ mem = TRUE;
+ }
+
+ if (!mem)
+ tool_oom ("building message");
+ }
+
+ if (no_reply)
+ {
+ if (!dbus_connection_send (connection, message, NULL))
+ tool_oom ("sending message");
+
+ VERBOSE (stderr, "sent message #%d\n", sent);
+ sent++;
+ sent_in_this_conn++;
+ }
+ else
+ {
+ DBusPendingCall *pc;
+
+ if (!dbus_connection_send_with_reply (connection,
+ message,
+ &pc,
+ DBUS_TIMEOUT_INFINITE))
+ tool_oom ("sending message");
+
+ VERBOSE (stderr, "sent message #%d\n", sent);
+ sent++;
+ sent_in_this_conn++;
+
+ if (pc == NULL)
+ tool_oom ("sending message");
+
+ if (dbus_pending_call_get_completed (pc))
+ pc_notify (pc, &received);
+ else if (!dbus_pending_call_set_notify (pc, pc_notify, &received,
+ NULL))
+ tool_oom ("setting pending call notifier");
+
+ dbus_pending_call_unref (pc);
+ }
+
+ dbus_message_unref (message);
+ }
+
+ if (!dbus_connection_read_write_dispatch (connection, -1))
+ {
+ fprintf (stderr, "Disconnected from bus\n");
+ exit (1);
+ }
+ }
+
+ if (connection != NULL)
+ {
+ dbus_connection_flush (connection);
+ dbus_connection_close (connection);
+ dbus_connection_unref (connection);
+ }
+
+ VERBOSE (stderr, "Done\n");
+
+ dbus_free (payload_buf);
+ dbus_free (random_sizes);
+
+ if (template != NULL)
+ dbus_message_unref (template);
+
+ dbus_shutdown ();
+ return 0;
+}
diff --git a/tools/dbus-update-activation-environment.c b/tools/dbus-update-activation-environment.c
new file mode 100644
index 00000000..6c53d8e2
--- /dev/null
+++ b/tools/dbus-update-activation-environment.c
@@ -0,0 +1,423 @@
+/*
+ * dbus-update-activation-environment - update D-Bus, and optionally
+ * systemd, activation environment
+ *
+ * Copyright © 2014-2015 Collabora Ltd.
+ *
+ * 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 AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_SYSEXITS_H
+# include <sysexits.h>
+#endif
+
+#include <dbus/dbus.h>
+
+#ifdef DBUS_UNIX
+# include <unistd.h>
+# include <sys/stat.h>
+# include <sys/types.h>
+#endif
+
+#include "tool-common.h"
+
+#define PROGNAME "dbus-update-activation-environment"
+
+#ifndef EX_USAGE
+# define EX_USAGE 64
+#endif
+
+#ifndef EX_UNAVAILABLE
+# define EX_UNAVAILABLE 69
+#endif
+
+#ifndef EX_OSERR
+# define EX_OSERR 71
+#endif
+
+#ifdef DBUS_WIN
+/* The Windows C runtime uses a different name */
+#define environ _environ
+#else
+/* apparently this is the portable way to get the entire environment...
+ * GNU platforms also put it in unistd.h but that's not portable */
+extern char **environ;
+#endif
+
+/* we don't really have anything useful to say about the stage at which we
+ * failed */
+#define oom() tool_oom ("updating environment")
+
+static dbus_bool_t verbose = FALSE;
+
+static void say (const char *format, ...) _DBUS_GNUC_PRINTF (1, 2);
+
+static void
+say (const char *format,
+ ...)
+{
+ va_list ap;
+
+ if (!verbose)
+ return;
+
+ fprintf (stderr, "%s: ", PROGNAME);
+ va_start (ap, format);
+ vfprintf (stderr, format, ap);
+ fputc ('\n', stderr);
+ va_end (ap);
+}
+
+#ifdef __linux__
+static dbus_bool_t
+systemd_user_running (void)
+{
+ char *xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR");
+ char *path;
+ struct stat buf;
+ dbus_bool_t ret = FALSE;
+
+ if (xdg_runtime_dir == NULL)
+ return FALSE;
+
+ /* Assume that XDG_RUNTIME_DIR/systemd exists if and only if
+ * "systemd --user" is running. It's OK to use asprintf() here
+ * because we know we're on Linux. */
+ if (asprintf (&path, "%s/systemd", xdg_runtime_dir) < 0)
+ oom ();
+
+ if (stat (path, &buf) == 0)
+ ret = TRUE;
+
+ free (path);
+ return ret;
+}
+#endif
+
+int
+main (int argc, char **argv)
+{
+ DBusConnection *conn;
+ DBusMessage *msg;
+ DBusMessage *reply;
+ DBusError error = DBUS_ERROR_INIT;
+ DBusMessageIter msg_iter;
+ DBusMessageIter array_iter;
+ int i;
+ int first_non_option = argc;
+ dbus_bool_t all = FALSE;
+#ifdef __linux__
+ DBusMessage *sd_msg = NULL;
+ DBusMessageIter sd_msg_iter;
+ DBusMessageIter sd_array_iter;
+ dbus_bool_t systemd = FALSE;
+#endif
+
+ for (i = 1; i < argc; i++)
+ {
+ if (argv[i][0] != '-')
+ {
+ first_non_option = i;
+ break;
+ }
+ else if (strcmp (argv[i], "--") == 0)
+ {
+ first_non_option = i + 1;
+ break;
+ }
+ else if (strcmp (argv[i], "--all") == 0)
+ {
+ all = TRUE;
+ }
+ else if (strcmp (argv[i], "--systemd") == 0)
+ {
+#ifdef __linux__
+ systemd = TRUE;
+#else
+ say ("not on Linux, ignoring --systemd argument");
+#endif
+ }
+ else if (strcmp (argv[i], "--verbose") == 0)
+ {
+ verbose = TRUE;
+ }
+ else
+ {
+ fprintf (stderr,
+ "%1$s: update environment variables that will be set for D-Bus\n"
+ " session services\n"
+ "\n"
+ "%1$s [options] VAR[=VAL] [VAR2[=VAL2] ...]\n"
+ " Add specified variables to D-Bus activation environment.\n"
+ " If omitted, values are taken from current environment;\n"
+ " variables not found in the environment are ignored.\n"
+ "%1$s --all\n"
+ " Add entire current environment to D-Bus activation\n"
+ " environment.\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ "--all\n"
+ " Upload all environment variables.\n"
+ "--systemd\n"
+ " Also update the 'systemd --user' environment\n"
+ " if possible.\n"
+ "--verbose\n"
+ " Talk about it.\n"
+ ,
+ PROGNAME);
+ exit (EX_USAGE);
+ }
+ }
+
+ if (all && first_non_option < argc)
+ {
+ fprintf (stderr, "%s: error: --all cannot be used with VAR or "
+ "VAR=VAL arguments\n", PROGNAME);
+ exit (EX_USAGE);
+ }
+
+ conn = dbus_bus_get (DBUS_BUS_SESSION, &error);
+
+ if (conn == NULL)
+ {
+ fprintf (stderr,
+ "%s: error: unable to connect to D-Bus: %s\n", PROGNAME,
+ error.message);
+ exit (EX_OSERR);
+ }
+
+ msg = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS, "UpdateActivationEnvironment");
+
+ if (msg == NULL)
+ oom ();
+
+ dbus_message_iter_init_append (msg, &msg_iter);
+
+ if (!dbus_message_iter_open_container (&msg_iter, DBUS_TYPE_ARRAY,
+ "{ss}", &array_iter))
+ oom ();
+
+#ifdef __linux__
+ if (systemd)
+ {
+ if (!systemd_user_running ())
+ {
+ /* This is only best-effort. */
+ say ("systemd --user not found, ignoring --systemd argument");
+ systemd = FALSE;
+ }
+ }
+
+ if (systemd)
+ {
+ sd_msg = dbus_message_new_method_call ("org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager",
+ "SetEnvironment");
+
+ if (sd_msg == NULL)
+ oom ();
+
+ dbus_message_iter_init_append (sd_msg, &sd_msg_iter);
+
+ if (!dbus_message_iter_open_container (&sd_msg_iter, DBUS_TYPE_ARRAY,
+ "s", &sd_array_iter))
+ oom ();
+ }
+#endif
+
+ for (i = all ? 0 : first_non_option;
+ all ? environ[i] != NULL : i < argc;
+ i++)
+ {
+ const char *var;
+ char *copy;
+ char *eq;
+ const char *val;
+ DBusMessageIter pair_iter;
+
+ if (all)
+ var = environ[i];
+ else
+ var = argv[i];
+
+ copy = strdup (var);
+
+ if (copy == NULL)
+ oom ();
+
+ if (!dbus_validate_utf8 (var, NULL))
+ {
+ /* var is either of the form VAR or VAR=VAL */
+ fprintf (stderr,
+ "%s: warning: environment variable not UTF-8: %s\n",
+ PROGNAME, var);
+ goto next;
+ }
+
+ eq = strchr (copy, '=');
+
+ if (eq == NULL)
+ {
+ if (all)
+ {
+ /* items in the environment block should be of the form
+ * VAR=VAL */
+ fprintf (stderr,
+ "%s: warning: environment variable without '=': %s\n",
+ PROGNAME, var);
+ goto next;
+ }
+ else
+ {
+ /* items on the command-line may be of the form VAR
+ * in which case we infer the value from the environment */
+ val = getenv (var);
+
+ if (val == NULL)
+ {
+ /* nothing to be done here */
+ goto next;
+ }
+
+ if (!dbus_validate_utf8 (val, NULL))
+ {
+ fprintf (stderr,
+ "%s: warning: environment variable not UTF-8: %s=%s\n",
+ PROGNAME, var, val);
+ goto next;
+ }
+ }
+ }
+ else
+ {
+ /* split VAR=VAL into VAR and VAL */
+ *eq = '\0';
+ val = eq + 1;
+ }
+
+#ifdef __linux__
+ if (systemd)
+ {
+ char *combined;
+
+ /* recombine if necessary */
+ if (asprintf (&combined, "%s=%s", copy, val) < 0)
+ oom ();
+
+ if (!dbus_message_iter_append_basic (&sd_array_iter,
+ DBUS_TYPE_STRING, &combined))
+ oom ();
+
+ free (combined);
+ }
+#endif
+
+ if (!dbus_message_iter_open_container (&array_iter,
+ DBUS_TYPE_DICT_ENTRY, NULL, &pair_iter))
+ oom ();
+
+ say ("setting %s=%s", copy, val);
+
+ if (!dbus_message_iter_append_basic (&pair_iter, DBUS_TYPE_STRING,
+ &copy))
+ oom ();
+
+ if (!dbus_message_iter_append_basic (&pair_iter, DBUS_TYPE_STRING,
+ &val))
+ oom ();
+
+ if (!dbus_message_iter_close_container (&array_iter, &pair_iter))
+ oom ();
+
+next:
+ free (copy);
+ }
+
+ if (!dbus_message_iter_close_container (&msg_iter, &array_iter))
+ oom ();
+
+#ifdef __linux__
+ if (systemd &&
+ !dbus_message_iter_close_container (&sd_msg_iter, &sd_array_iter))
+ oom ();
+#endif
+
+ reply = dbus_connection_send_with_reply_and_block (conn, msg, -1, &error);
+
+ if (reply == NULL)
+ {
+ fprintf (stderr,
+ "%s: error sending to dbus-daemon: %s: %s\n",
+ PROGNAME, error.name, error.message);
+ exit (EX_UNAVAILABLE);
+ }
+
+ if (!dbus_message_get_args (msg, &error, DBUS_TYPE_INVALID))
+ {
+ fprintf (stderr,
+ "%s: error from dbus-daemon: %s: %s\n",
+ PROGNAME, error.name, error.message);
+ exit (EX_UNAVAILABLE);
+ }
+
+ dbus_message_unref (reply);
+
+#ifdef __linux__
+ if (systemd)
+ {
+ reply = dbus_connection_send_with_reply_and_block (conn, sd_msg, -1,
+ &error);
+
+ /* non-fatal, the main purpose of this thing is to communicate
+ * with dbus-daemon */
+ if (reply == NULL)
+ {
+ fprintf (stderr,
+ "%s: warning: error sending to systemd: %s: %s\n",
+ PROGNAME, error.name, error.message);
+ }
+ else if (!dbus_message_get_args (msg, &error, DBUS_TYPE_INVALID))
+ {
+ fprintf (stderr,
+ "%s: warning: error from systemd: %s: %s\n",
+ PROGNAME, error.name, error.message);
+ }
+
+ if (reply != NULL)
+ dbus_message_unref (reply);
+
+ dbus_message_unref (sd_msg);
+ dbus_error_free (&error);
+ }
+#endif
+
+ dbus_message_unref (msg);
+ dbus_connection_unref (conn);
+ return 0;
+}
diff --git a/tools/dbus-uuidgen.c b/tools/dbus-uuidgen.c
index c8ba1cf7..03ce5536 100644
--- a/tools/dbus-uuidgen.c
+++ b/tools/dbus-uuidgen.c
@@ -137,15 +137,12 @@ main (int argc, char *argv[])
else
{
char *uuid;
- if (dbus_internal_do_not_use_create_uuid (&uuid))
+
+ if (_dbus_create_uuid (&uuid, &error))
{
printf ("%s\n", uuid);
dbus_free (uuid);
}
- else
- {
- dbus_set_error (&error, DBUS_ERROR_NO_MEMORY, "No memory");
- }
}
if (dbus_error_is_set (&error))
diff --git a/tools/lcov.am b/tools/lcov.am
index 7ba49912..ac348671 100644
--- a/tools/lcov.am
+++ b/tools/lcov.am
@@ -21,10 +21,10 @@
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
lcov-reset:
- lcov --directory @abs_top_srcdir@ --zerocounters
+ lcov --directory @abs_top_builddir@ --zerocounters
lcov-report:
- lcov --directory @abs_top_srcdir@ --capture \
+ lcov --directory @abs_top_builddir@ --capture \
--output-file @abs_top_builddir@/lcov.info
$(mkdir_p) @abs_top_builddir@/lcov.html
git_commit=`GIT_DIR=@abs_top_srcdir@/.git git log -1 --pretty=format:%h 2>/dev/null`;\
diff --git a/tools/test-tool.c b/tools/test-tool.c
new file mode 100644
index 00000000..149c10ab
--- /dev/null
+++ b/tools/test-tool.c
@@ -0,0 +1,88 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* dbus-test-tool - D-Bus swiss army knife
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * This program is free software; you can 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.h>
+#include "test-tool.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <dbus/dbus.h>
+
+static struct {
+ const char *name;
+ int (*callback) (int, char **);
+} subcommands[] = {
+ { "black-hole", dbus_test_tool_black_hole },
+ { "echo", dbus_test_tool_echo },
+ { "spam", dbus_test_tool_spam },
+ { NULL, NULL }
+};
+
+static void usage (int exit_with) _DBUS_GNUC_NORETURN;
+
+static void
+usage (int exit_with)
+{
+ int i;
+
+ fprintf (stderr,
+ "Usage: dbus-test-tool SUBCOMMAND [OPTIONS]\n"
+ "\n"
+ "Known SUBCOMMANDs are:\n"
+ "\n"
+ );
+
+ for (i = 0; subcommands[i].name != NULL; i++)
+ {
+ fprintf (stderr, "- %s\n", subcommands[i].name);
+ }
+
+ fprintf (stderr,
+ "\n"
+ "For more information: dbus-test-tool SUBCOMMAND --help\n"
+ );
+
+ exit (exit_with);
+}
+
+int
+main (int argc, char **argv)
+{
+ int i;
+
+ if (argc < 2)
+ {
+ usage (2);
+ }
+
+ for (i = 0; subcommands[i].name != NULL; i++)
+ {
+ if (!strcmp (argv[1], subcommands[i].name))
+ return subcommands[i].callback (argc, argv);
+ }
+
+ usage (2);
+ return 2;
+}
diff --git a/tools/test-tool.h b/tools/test-tool.h
new file mode 100644
index 00000000..8143cd50
--- /dev/null
+++ b/tools/test-tool.h
@@ -0,0 +1,31 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* dbus-test-tool - D-Bus swiss army knife
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * This program is free software; you can 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_TOOL_H
+#define DBUS_TEST_TOOL_H
+
+int dbus_test_tool_black_hole (int argc, char **argv);
+int dbus_test_tool_echo (int argc, char **argv);
+int dbus_test_tool_spam (int argc, char **argv);
+
+#endif
diff --git a/tools/tool-common.c b/tools/tool-common.c
new file mode 100644
index 00000000..32020324
--- /dev/null
+++ b/tools/tool-common.c
@@ -0,0 +1,82 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* tool-common - common functionality for dbus-test-tool modules
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * This program is free software; you can 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.h>
+#include "tool-common.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef DBUS_WIN
+#include <io.h>
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+void
+tool_oom (const char *doing)
+{
+ fprintf (stderr, "OOM while %s\n", doing);
+ exit (1);
+}
+
+#ifdef DBUS_WIN
+typedef int WriteResult;
+#define write(fd, buf, len) _write(fd, buf, len)
+#else
+typedef ssize_t WriteResult;
+#endif
+
+dbus_bool_t
+tool_write_all (int fd,
+ const void *buf,
+ size_t size)
+{
+ const char *p = buf;
+ size_t bytes_written = 0;
+
+ while (size > bytes_written)
+ {
+ WriteResult res = write (fd, p, size - bytes_written);
+
+ if (res < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ else
+ return FALSE;
+ }
+ else
+ {
+ size_t this_time = (size_t) res;
+ p += this_time;
+ bytes_written += this_time;
+ }
+ }
+
+ return TRUE;
+}
diff --git a/tools/tool-common.h b/tools/tool-common.h
new file mode 100644
index 00000000..e6397ffb
--- /dev/null
+++ b/tools/tool-common.h
@@ -0,0 +1,38 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* tool-common - common functionality for dbus-test-tool modules
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * This program is free software; you can 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_TOOL_COMMON_H
+#define DBUS_TOOL_COMMON_H
+
+#include <dbus/dbus.h>
+
+#if 0
+#define VERBOSE fprintf
+#else
+#define VERBOSE(...) do {} while (0)
+#endif
+
+void tool_oom (const char *doing) _DBUS_GNUC_NORETURN;
+dbus_bool_t tool_write_all (int fd, const void *buf, size_t size);
+
+#endif