dbus-monitor: add support for using BecomeMonitor to be a read-only monitor
authorSimon McVittie <simon.mcvittie@collabora.co.uk>
Mon, 2 Feb 2015 20:08:07 +0000 (20:08 +0000)
committerSimon McVittie <simon.mcvittie@collabora.co.uk>
Wed, 4 Feb 2015 17:15:31 +0000 (17:15 +0000)
Move the dbus_connection_add_filter() call further up as a precaution,
because it isn't safe for a monitor to not have a filter that
swallows all messages.

Bug: https://bugs.freedesktop.org/show_bug.cgi?id=46787
Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
tools/dbus-monitor.c

index c15589a4dbdb349aaee467aadfc53e2f7cd73b8b..5792112caee5bd9835144ba51b13c95ae1cce3f0 100644 (file)
@@ -90,10 +90,9 @@ monitor_filter_func (DBusConnection     *connection,
                               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;
 }
@@ -236,6 +235,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[])
 {
@@ -359,7 +418,18 @@ main (int argc, char *argv[])
       exit (1);
     }
 
-  if (numFilters)
+  if (!dbus_connection_add_filter (connection, filter_func, NULL, 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++)
@@ -402,10 +472,6 @@ main (int argc, char *argv[])
         }
     }
 
-  if (!dbus_connection_add_filter (connection, filter_func, NULL, NULL)) {
-    fprintf (stderr, "Couldn't add filter!\n");
-    exit (1);
-  }
 
   while (dbus_connection_read_write_dispatch(connection, -1))
     ;