summaryrefslogtreecommitdiff
path: root/bus
diff options
context:
space:
mode:
Diffstat (limited to 'bus')
-rw-r--r--bus/Makefile.am29
-rw-r--r--bus/activation.c8
-rw-r--r--bus/connection.c7
-rw-r--r--bus/dir-watch-inotify.c6
-rw-r--r--bus/dir-watch-kqueue.c18
-rw-r--r--bus/dispatch.c169
-rw-r--r--bus/driver.c1
-rw-r--r--bus/example-session-disable-stats.conf.in15
-rw-r--r--bus/example-system-enable-stats.conf.in15
-rw-r--r--bus/signals.c184
-rw-r--r--bus/signals.h6
-rw-r--r--bus/stats.c117
-rw-r--r--bus/stats.h5
-rw-r--r--bus/system.conf.in15
-rw-r--r--bus/test-main.c9
15 files changed, 545 insertions, 59 deletions
diff --git a/bus/Makefile.am b/bus/Makefile.am
index f335e30c..c0bc1549 100644
--- a/bus/Makefile.am
+++ b/bus/Makefile.am
@@ -31,11 +31,22 @@ EFENCE=
CONFIG_IN_FILES= \
session.conf.in \
system.conf.in \
- org.freedesktop.dbus-session.plist.in
+ org.freedesktop.dbus-session.plist.in \
+ example-system-enable-stats.conf.in \
+ example-session-disable-stats.conf.in \
+ $(NULL)
+
+config_DATA = session.conf
+
+if DBUS_UNIX
+config_DATA += 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)
@@ -169,11 +180,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
@@ -203,11 +214,13 @@ clean-local:
/bin/rm *.bb *.bbg *.da *.gcov || true
install-data-hook:
- $(mkinstalldirs) $(DESTDIR)$(localstatedir)/run/dbus
- $(mkinstalldirs) $(DESTDIR)$(configdir)/system.d
$(mkinstalldirs) $(DESTDIR)$(configdir)/session.d
$(mkinstalldirs) $(DESTDIR)$(datadir)/dbus-1/services
+if DBUS_UNIX
+ $(mkinstalldirs) $(DESTDIR)$(localstatedir)/run/dbus
+ $(mkinstalldirs) $(DESTDIR)$(configdir)/system.d
$(mkinstalldirs) $(DESTDIR)$(datadir)/dbus-1/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,
diff --git a/bus/activation.c b/bus/activation.c
index ecd19bb4..ffedf4c5 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;
}
diff --git a/bus/connection.c b/bus/connection.c
index 519122c5..0df8a3a8 100644
--- a/bus/connection.c
+++ b/bus/connection.c
@@ -1619,7 +1619,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;
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..8f322f8c 100644
--- a/bus/dispatch.c
+++ b/bus/dispatch.c
@@ -433,6 +433,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.
@@ -1310,6 +1312,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 +1400,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 +1424,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 +1528,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 +1694,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 +4649,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 +4664,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 +4679,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 +4806,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 +4886,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))
@@ -4794,7 +4935,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,7 +4950,7 @@ 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")))
diff --git a/bus/driver.c b/bus/driver.c
index e95a79d9..777b2f89 100644
--- a/bus/driver.c
+++ b/bus/driver.c
@@ -1789,6 +1789,7 @@ static const MessageHandler introspectable_message_handlers[] = {
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
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/signals.c b/bus/signals.c
index 4c500c67..119d8130 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,
@@ -1141,6 +1173,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 +1459,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 +1552,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 +1589,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 +2066,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
@@ -2401,7 +2501,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 +2519,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 +2536,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..d19fc7c5 100644
--- a/bus/signals.h
+++ b/bus/signals.h
@@ -77,6 +77,12 @@ 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 24308eb5..859c6a52 100644
--- a/bus/stats.c
+++ b/bus/stats.c
@@ -30,6 +30,7 @@
#include "connection.h"
#include "services.h"
+#include "signals.h"
#include "utils.h"
#ifdef DBUS_ENABLE_STATS
@@ -217,4 +218,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 92f4cc42..c1541bff 100644
--- a/bus/system.conf.in
+++ b/bus/system.conf.in
@@ -63,11 +63,24 @@
<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"/>
+ </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>
<!-- Config files are placed here that among other things, punch
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");