[glib] gdbus: Add --recurse and --only-properties options



commit 30dfc353920df56e31555d9e58a690d9d552058f
Author: David Zeuthen <davidz redhat com>
Date:   Thu Jun 9 13:22:18 2011 -0400

    gdbus: Add --recurse and --only-properties options
    
    These options are useful when debugging D-Bus services and working
    with bug reports.
    
    Signed-off-by: David Zeuthen <davidz redhat com>

 docs/reference/gio/gdbus.xml |   47 +++++++++++-
 gio/gdbus-tool.c             |  185 ++++++++++++++++++++++++++++++------------
 2 files changed, 178 insertions(+), 54 deletions(-)
---
diff --git a/docs/reference/gio/gdbus.xml b/docs/reference/gio/gdbus.xml
index 7729f85..4c81ce9 100644
--- a/docs/reference/gio/gdbus.xml
+++ b/docs/reference/gio/gdbus.xml
@@ -25,6 +25,12 @@
     <group>
       <arg choice="plain">--xml</arg>
     </group>
+    <group>
+      <arg choice="plain">--recurse</arg>
+    </group>
+    <group>
+      <arg choice="plain">--only-properties</arg>
+    </group>
   </cmdsynopsis>
   <cmdsynopsis>
     <command>gdbus</command>
@@ -94,7 +100,12 @@
           <literal>org.freedesktop.DBus.Introspectable</literal> interface.
           If the <option>--xml</option> option is used, the returned
           introspection XML is printed, otherwise a parsed pretty
-          representation is printed.  </para></listitem>
+          representation is printed.
+          The <option>--recurse</option> option can be used to
+          introspect children (and their children and so on) and the
+          <option>--only-properties</option> option can be used to
+          only print the interfaces with properties.
+          </para></listitem>
       </varlistentry>
       <varlistentry>
         <term><option>monitor</option></term>
@@ -196,6 +207,40 @@ node /org/freedesktop/NetworkManager/Devices/0 {
 };
 </programlisting>
 <para>
+  The <option>--recurse</option> and <option>--only-properties</option> options can be useful when wanting to inspect all objects owned by a particular process:
+</para>
+<programlisting>
+$ gdbus introspect --system --dest org.freedesktop.UPower --object-path / --recurse  --only-properties 
+node / {
+  node /org {
+    node /org/freedesktop {
+      node /org/freedesktop/UPower {
+        interface org.freedesktop.UPower {
+          properties:
+            readonly b IsDocked = true;
+            readonly b LidForceSleep = false;
+            readonly b LidIsPresent = false;
+            readonly b LidIsClosed = false;
+            readonly b OnLowBattery = false;
+            readonly b OnBattery = false;
+            readonly b CanHibernate = true;
+            readonly b CanSuspend = true;
+            readonly s DaemonVersion = '0.9.10';
+        };
+        node /org/freedesktop/UPower/Policy {
+        };
+        node /org/freedesktop/UPower/Wakeups {
+          interface org.freedesktop.UPower.Wakeups {
+            properties:
+              readonly b HasCapability = true;
+          };
+        };
+      };
+    };
+  };
+};
+</programlisting>
+<para>
   In a similar fashion, the <option>introspect</option> command can be
   used to learn details about the <literal>Notify</literal> method:
 </para>
diff --git a/gio/gdbus-tool.c b/gio/gdbus-tool.c
index 9fb52fc..454528b 100644
--- a/gio/gdbus-tool.c
+++ b/gio/gdbus-tool.c
@@ -1049,7 +1049,11 @@ handle_call (gint        *argc,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-/* TODO: dump annotations */
+static gchar *opt_introspect_dest = NULL;
+static gchar *opt_introspect_object_path = NULL;
+static gboolean opt_introspect_xml = FALSE;
+static gboolean opt_introspect_recurse = FALSE;
+static gboolean opt_introspect_only_properties = FALSE;
 
 static void
 dump_annotation (const GDBusAnnotationInfo *o,
@@ -1287,13 +1291,13 @@ dump_interface (GDBusConnection          *c,
     dump_annotation (o->annotations[n], indent, FALSE);
 
   g_print ("%*sinterface %s {\n", indent, "", o->name);
-  if (o->methods != NULL)
+  if (o->methods != NULL && !opt_introspect_only_properties)
     {
       g_print ("%*s  methods:\n", indent, "");
       for (n = 0; o->methods[n] != NULL; n++)
         dump_method (o->methods[n], indent + 4);
     }
-  if (o->signals != NULL)
+  if (o->signals != NULL && !opt_introspect_only_properties)
     {
       g_print ("%*s  signals:\n", indent, "");
       for (n = 0; o->signals[n] != NULL; n++)
@@ -1315,12 +1319,18 @@ dump_interface (GDBusConnection          *c,
   g_hash_table_unref (properties);
 }
 
+static gboolean
+introspect_do (GDBusConnection *c,
+               const gchar     *object_path,
+               guint            indent);
+
 static void
 dump_node (GDBusConnection      *c,
            const gchar          *name,
            const GDBusNodeInfo  *o,
            guint                 indent,
-           const gchar          *object_path)
+           const gchar          *object_path,
+           gboolean              recurse)
 {
   guint n;
   const gchar *object_path_to_print;
@@ -1337,9 +1347,51 @@ dump_node (GDBusConnection      *c,
     {
       g_print (" {\n");
       for (n = 0; o->interfaces != NULL && o->interfaces[n] != NULL; n++)
-        dump_interface (c, name, o->interfaces[n], indent + 2, object_path);
+        {
+          if (opt_introspect_only_properties)
+            {
+              if (o->interfaces[n]->properties != NULL && o->interfaces[n]->properties[0] != NULL)
+                dump_interface (c, name, o->interfaces[n], indent + 2, object_path);
+            }
+          else
+            {
+              dump_interface (c, name, o->interfaces[n], indent + 2, object_path);
+            }
+        }
       for (n = 0; o->nodes != NULL && o->nodes[n] != NULL; n++)
-        dump_node (NULL, NULL, o->nodes[n], indent + 2, NULL);
+        {
+          if (recurse)
+            {
+              gchar *child_path;
+              if (g_variant_is_object_path (o->nodes[n]->path))
+                {
+                  child_path = g_strdup (o->nodes[n]->path);
+                  /* avoid infinite loops */
+                  if (g_str_has_prefix (child_path, object_path))
+                    {
+                      introspect_do (c, child_path, indent + 2);
+                    }
+                  else
+                    {
+                      g_print ("Skipping path %s that is not enclosed by parent %s\n",
+                               child_path, object_path);
+                    }
+                }
+              else
+                {
+                  if (g_strcmp0 (object_path, "/") == 0)
+                    child_path = g_strdup_printf ("/%s", o->nodes[n]->path);
+                  else
+                    child_path = g_strdup_printf ("%s/%s", object_path, o->nodes[n]->path);
+                  introspect_do (c, child_path, indent + 2);
+                }
+              g_free (child_path);
+            }
+          else
+            {
+              dump_node (NULL, NULL, o->nodes[n], indent + 2, NULL, recurse);
+            }
+        }
       g_print ("%*s};\n",
                indent, "");
     }
@@ -1349,19 +1401,79 @@ dump_node (GDBusConnection      *c,
     }
 }
 
-static gchar *opt_introspect_dest = NULL;
-static gchar *opt_introspect_object_path = NULL;
-static gboolean opt_introspect_xml = FALSE;
-
 static const GOptionEntry introspect_entries[] =
 {
   { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_introspect_dest, N_("Destination name to introspect"), NULL},
   { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_introspect_object_path, N_("Object path to introspect"), NULL},
   { "xml", 'x', 0, G_OPTION_ARG_NONE, &opt_introspect_xml, N_("Print XML"), NULL},
+  { "recurse", 'r', 0, G_OPTION_ARG_NONE, &opt_introspect_recurse, N_("Introspect children"), NULL},
+  { "only-properties", 'p', 0, G_OPTION_ARG_NONE, &opt_introspect_only_properties, N_("Only print properties"), NULL},
   { NULL }
 };
 
 static gboolean
+introspect_do (GDBusConnection *c,
+               const gchar     *object_path,
+               guint            indent)
+{
+  GError *error;
+  GVariant *result;
+  GDBusNodeInfo *node;
+  gboolean ret;
+  const gchar *xml_data;
+
+  ret = FALSE;
+  node = NULL;
+  result = NULL;
+
+  result = g_dbus_connection_call_sync (c,
+                                        opt_introspect_dest,
+                                        object_path,
+                                        "org.freedesktop.DBus.Introspectable",
+                                        "Introspect",
+                                        NULL,
+                                        G_VARIANT_TYPE ("(s)"),
+                                        G_DBUS_CALL_FLAGS_NONE,
+                                        3000, /* 3 sec */
+                                        NULL,
+                                        &error);
+  if (result == NULL)
+    {
+      g_printerr (_("Error: %s\n"), error->message);
+      g_error_free (error);
+      goto out;
+    }
+  g_variant_get (result, "(&s)", &xml_data);
+
+  if (opt_introspect_xml)
+    {
+      g_print ("%s", xml_data);
+    }
+  else
+    {
+      error = NULL;
+      node = g_dbus_node_info_new_for_xml (xml_data, &error);
+      if (node == NULL)
+        {
+          g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
+          g_error_free (error);
+          goto out;
+        }
+
+      dump_node (c, opt_introspect_dest, node, indent, object_path, opt_introspect_recurse);
+    }
+
+  ret = TRUE;
+
+ out:
+  if (node != NULL)
+    g_dbus_node_info_unref (node);
+  if (result != NULL)
+    g_variant_unref (result);
+  return ret;
+}
+
+static gboolean
 handle_introspect (gint        *argc,
                    gchar      **argv[],
                    gboolean     request_completion,
@@ -1373,16 +1485,11 @@ handle_introspect (gint        *argc,
   gchar *s;
   GError *error;
   GDBusConnection *c;
-  GVariant *result;
-  const gchar *xml_data;
-  GDBusNodeInfo *node;
   gboolean complete_names;
   gboolean complete_paths;
 
   ret = FALSE;
   c = NULL;
-  node = NULL;
-  result = NULL;
 
   modify_argv0_for_command (argc, argv, "introspect");
 
@@ -1500,54 +1607,26 @@ handle_introspect (gint        *argc,
       goto out;
     }
 
-  /* All done with completion now */
-  if (request_completion)
-    goto out;
-
-  result = g_dbus_connection_call_sync (c,
-                                        opt_introspect_dest,
-                                        opt_introspect_object_path,
-                                        "org.freedesktop.DBus.Introspectable",
-                                        "Introspect",
-                                        NULL,
-                                        G_VARIANT_TYPE ("(s)"),
-                                        G_DBUS_CALL_FLAGS_NONE,
-                                        3000, /* 3 sec */
-                                        NULL,
-                                        &error);
-  if (result == NULL)
+  if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_recurse)
     {
-      g_printerr (_("Error: %s\n"), error->message);
-      g_error_free (error);
-      goto out;
+      g_print ("--recurse \n");
     }
-  g_variant_get (result, "(&s)", &xml_data);
 
-  if (opt_introspect_xml)
+  if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_only_properties)
     {
-      g_print ("%s", xml_data);
+      g_print ("--only-properties \n");
     }
-  else
-    {
-      error = NULL;
-      node = g_dbus_node_info_new_for_xml (xml_data, &error);
-      if (node == NULL)
-        {
-          g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
-          g_error_free (error);
-          goto out;
-        }
 
-      dump_node (c, opt_introspect_dest, node, 0, opt_introspect_object_path);
-    }
+  /* All done with completion now */
+  if (request_completion)
+    goto out;
+
+  if (!introspect_do (c, opt_introspect_object_path, 0))
+    goto out;
 
   ret = TRUE;
 
  out:
-  if (node != NULL)
-    g_dbus_node_info_unref (node);
-  if (result != NULL)
-    g_variant_unref (result);
   if (c != NULL)
     g_object_unref (c);
   g_option_context_free (o);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]