diff options
Diffstat (limited to 'bus')
-rw-r--r-- | bus/Makefile.am | 29 | ||||
-rw-r--r-- | bus/activation.c | 8 | ||||
-rw-r--r-- | bus/connection.c | 7 | ||||
-rw-r--r-- | bus/dir-watch-inotify.c | 6 | ||||
-rw-r--r-- | bus/dir-watch-kqueue.c | 18 | ||||
-rw-r--r-- | bus/dispatch.c | 169 | ||||
-rw-r--r-- | bus/driver.c | 1 | ||||
-rw-r--r-- | bus/example-session-disable-stats.conf.in | 15 | ||||
-rw-r--r-- | bus/example-system-enable-stats.conf.in | 15 | ||||
-rw-r--r-- | bus/signals.c | 184 | ||||
-rw-r--r-- | bus/signals.h | 6 | ||||
-rw-r--r-- | bus/stats.c | 117 | ||||
-rw-r--r-- | bus/stats.h | 5 | ||||
-rw-r--r-- | bus/system.conf.in | 15 | ||||
-rw-r--r-- | bus/test-main.c | 9 |
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"); |