2.54.2
[glib.git] / gio / gdbus-tool.c
blobfb285f1db9181f1eb729ce2c0363a6da0571494b
1 /* GDBus - GLib D-Bus Library
3 * Copyright (C) 2008-2010 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 * Author: David Zeuthen <davidz@redhat.com>
21 #include "config.h"
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <locale.h>
28 #include <gio/gio.h>
30 #include <gi18n.h>
32 #ifdef G_OS_WIN32
33 #include "glib/glib-private.h"
34 #endif
36 /* ---------------------------------------------------------------------------------------------------- */
38 G_GNUC_UNUSED static void completion_debug (const gchar *format, ...);
40 /* Uncomment to get debug traces in /tmp/gdbus-completion-debug.txt (nice
41 * to not have it interfere with stdout/stderr)
43 #if 0
44 G_GNUC_UNUSED static void
45 completion_debug (const gchar *format, ...)
47 va_list var_args;
48 gchar *s;
49 static FILE *f = NULL;
51 va_start (var_args, format);
52 s = g_strdup_vprintf (format, var_args);
53 if (f == NULL)
55 f = fopen ("/tmp/gdbus-completion-debug.txt", "a+");
57 fprintf (f, "%s\n", s);
58 g_free (s);
60 #else
61 static void
62 completion_debug (const gchar *format, ...)
65 #endif
67 /* ---------------------------------------------------------------------------------------------------- */
70 static void
71 remove_arg (gint num, gint *argc, gchar **argv[])
73 gint n;
75 g_assert (num <= (*argc));
77 for (n = num; (*argv)[n] != NULL; n++)
78 (*argv)[n] = (*argv)[n+1];
79 (*argv)[n] = NULL;
80 (*argc) = (*argc) - 1;
83 static void
84 usage (gint *argc, gchar **argv[], gboolean use_stdout)
86 GOptionContext *o;
87 gchar *s;
88 gchar *program_name;
90 o = g_option_context_new (_("COMMAND"));
91 g_option_context_set_help_enabled (o, FALSE);
92 /* Ignore parsing result */
93 g_option_context_parse (o, argc, argv, NULL);
94 program_name = g_path_get_basename ((*argv)[0]);
95 s = g_strdup_printf (_("Commands:\n"
96 " help Shows this information\n"
97 " introspect Introspect a remote object\n"
98 " monitor Monitor a remote object\n"
99 " call Invoke a method on a remote object\n"
100 " emit Emit a signal\n"
101 " wait Wait for a bus name to appear\n"
102 "\n"
103 "Use “%s COMMAND --help” to get help on each command.\n"),
104 program_name);
105 g_free (program_name);
106 g_option_context_set_description (o, s);
107 g_free (s);
108 s = g_option_context_get_help (o, FALSE, NULL);
109 if (use_stdout)
110 g_print ("%s", s);
111 else
112 g_printerr ("%s", s);
113 g_free (s);
114 g_option_context_free (o);
117 static void
118 modify_argv0_for_command (gint *argc, gchar **argv[], const gchar *command)
120 gchar *s;
121 gchar *program_name;
123 /* TODO:
124 * 1. get a g_set_prgname() ?; or
125 * 2. save old argv[0] and restore later
128 g_assert (g_strcmp0 ((*argv)[1], command) == 0);
129 remove_arg (1, argc, argv);
131 program_name = g_path_get_basename ((*argv)[0]);
132 s = g_strdup_printf ("%s %s", (*argv)[0], command);
133 (*argv)[0] = s;
134 g_free (program_name);
137 /* ---------------------------------------------------------------------------------------------------- */
139 static void
140 print_methods (GDBusConnection *c,
141 const gchar *name,
142 const gchar *path)
144 GVariant *result;
145 GError *error;
146 const gchar *xml_data;
147 GDBusNodeInfo *node;
148 guint n;
149 guint m;
151 error = NULL;
152 result = g_dbus_connection_call_sync (c,
153 name,
154 path,
155 "org.freedesktop.DBus.Introspectable",
156 "Introspect",
157 NULL,
158 G_VARIANT_TYPE ("(s)"),
159 G_DBUS_CALL_FLAGS_NONE,
160 3000, /* 3 secs */
161 NULL,
162 &error);
163 if (result == NULL)
165 g_printerr (_("Error: %s\n"), error->message);
166 g_error_free (error);
167 goto out;
169 g_variant_get (result, "(&s)", &xml_data);
171 error = NULL;
172 node = g_dbus_node_info_new_for_xml (xml_data, &error);
173 g_variant_unref (result);
174 if (node == NULL)
176 g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
177 g_error_free (error);
178 goto out;
181 for (n = 0; node->interfaces != NULL && node->interfaces[n] != NULL; n++)
183 const GDBusInterfaceInfo *iface = node->interfaces[n];
184 for (m = 0; iface->methods != NULL && iface->methods[m] != NULL; m++)
186 const GDBusMethodInfo *method = iface->methods[m];
187 g_print ("%s.%s \n", iface->name, method->name);
190 g_dbus_node_info_unref (node);
192 out:
196 static void
197 print_paths (GDBusConnection *c,
198 const gchar *name,
199 const gchar *path)
201 GVariant *result;
202 GError *error;
203 const gchar *xml_data;
204 GDBusNodeInfo *node;
205 guint n;
207 if (!g_dbus_is_name (name))
209 g_printerr (_("Error: %s is not a valid name\n"), name);
210 goto out;
213 error = NULL;
214 result = g_dbus_connection_call_sync (c,
215 name,
216 path,
217 "org.freedesktop.DBus.Introspectable",
218 "Introspect",
219 NULL,
220 G_VARIANT_TYPE ("(s)"),
221 G_DBUS_CALL_FLAGS_NONE,
222 3000, /* 3 secs */
223 NULL,
224 &error);
225 if (result == NULL)
227 g_printerr (_("Error: %s\n"), error->message);
228 g_error_free (error);
229 goto out;
231 g_variant_get (result, "(&s)", &xml_data);
233 //g_printerr ("xml='%s'", xml_data);
235 error = NULL;
236 node = g_dbus_node_info_new_for_xml (xml_data, &error);
237 g_variant_unref (result);
238 if (node == NULL)
240 g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
241 g_error_free (error);
242 goto out;
245 //g_printerr ("bar '%s'\n", path);
247 if (node->interfaces != NULL)
248 g_print ("%s \n", path);
250 for (n = 0; node->nodes != NULL && node->nodes[n] != NULL; n++)
252 gchar *s;
254 //g_printerr ("foo '%s'\n", node->nodes[n].path);
256 if (g_strcmp0 (path, "/") == 0)
257 s = g_strdup_printf ("/%s", node->nodes[n]->path);
258 else
259 s = g_strdup_printf ("%s/%s", path, node->nodes[n]->path);
261 print_paths (c, name, s);
263 g_free (s);
265 g_dbus_node_info_unref (node);
267 out:
271 static void
272 print_names (GDBusConnection *c,
273 gboolean include_unique_names)
275 GVariant *result;
276 GError *error;
277 GVariantIter *iter;
278 gchar *str;
279 GHashTable *name_set;
280 GList *keys;
281 GList *l;
283 name_set = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
285 error = NULL;
286 result = g_dbus_connection_call_sync (c,
287 "org.freedesktop.DBus",
288 "/org/freedesktop/DBus",
289 "org.freedesktop.DBus",
290 "ListNames",
291 NULL,
292 G_VARIANT_TYPE ("(as)"),
293 G_DBUS_CALL_FLAGS_NONE,
294 3000, /* 3 secs */
295 NULL,
296 &error);
297 if (result == NULL)
299 g_printerr (_("Error: %s\n"), error->message);
300 g_error_free (error);
301 goto out;
303 g_variant_get (result, "(as)", &iter);
304 while (g_variant_iter_loop (iter, "s", &str))
305 g_hash_table_insert (name_set, g_strdup (str), NULL);
306 g_variant_iter_free (iter);
307 g_variant_unref (result);
309 error = NULL;
310 result = g_dbus_connection_call_sync (c,
311 "org.freedesktop.DBus",
312 "/org/freedesktop/DBus",
313 "org.freedesktop.DBus",
314 "ListActivatableNames",
315 NULL,
316 G_VARIANT_TYPE ("(as)"),
317 G_DBUS_CALL_FLAGS_NONE,
318 3000, /* 3 secs */
319 NULL,
320 &error);
321 if (result == NULL)
323 g_printerr (_("Error: %s\n"), error->message);
324 g_error_free (error);
325 goto out;
327 g_variant_get (result, "(as)", &iter);
328 while (g_variant_iter_loop (iter, "s", &str))
329 g_hash_table_insert (name_set, g_strdup (str), NULL);
330 g_variant_iter_free (iter);
331 g_variant_unref (result);
333 keys = g_hash_table_get_keys (name_set);
334 keys = g_list_sort (keys, (GCompareFunc) g_strcmp0);
335 for (l = keys; l != NULL; l = l->next)
337 const gchar *name = l->data;
338 if (!include_unique_names && g_str_has_prefix (name, ":"))
339 continue;
341 g_print ("%s \n", name);
343 g_list_free (keys);
345 out:
346 g_hash_table_unref (name_set);
349 /* ---------------------------------------------------------------------------------------------------- */
351 static gboolean opt_connection_system = FALSE;
352 static gboolean opt_connection_session = FALSE;
353 static gchar *opt_connection_address = NULL;
355 static const GOptionEntry connection_entries[] =
357 { "system", 'y', 0, G_OPTION_ARG_NONE, &opt_connection_system, N_("Connect to the system bus"), NULL},
358 { "session", 'e', 0, G_OPTION_ARG_NONE, &opt_connection_session, N_("Connect to the session bus"), NULL},
359 { "address", 'a', 0, G_OPTION_ARG_STRING, &opt_connection_address, N_("Connect to given D-Bus address"), NULL},
360 { NULL }
363 static GOptionGroup *
364 connection_get_group (void)
366 static GOptionGroup *g;
368 g = g_option_group_new ("connection",
369 N_("Connection Endpoint Options:"),
370 N_("Options specifying the connection endpoint"),
371 NULL,
372 NULL);
373 g_option_group_set_translation_domain (g, GETTEXT_PACKAGE);
374 g_option_group_add_entries (g, connection_entries);
376 return g;
379 static GDBusConnection *
380 connection_get_dbus_connection (GError **error)
382 GDBusConnection *c;
384 c = NULL;
386 /* First, ensure we have exactly one connect */
387 if (!opt_connection_system && !opt_connection_session && opt_connection_address == NULL)
389 g_set_error (error,
390 G_IO_ERROR,
391 G_IO_ERROR_FAILED,
392 _("No connection endpoint specified"));
393 goto out;
395 else if ((opt_connection_system && (opt_connection_session || opt_connection_address != NULL)) ||
396 (opt_connection_session && (opt_connection_system || opt_connection_address != NULL)) ||
397 (opt_connection_address != NULL && (opt_connection_system || opt_connection_session)))
399 g_set_error (error,
400 G_IO_ERROR,
401 G_IO_ERROR_FAILED,
402 _("Multiple connection endpoints specified"));
403 goto out;
406 if (opt_connection_system)
408 c = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error);
410 else if (opt_connection_session)
412 c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error);
414 else if (opt_connection_address != NULL)
416 c = g_dbus_connection_new_for_address_sync (opt_connection_address,
417 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
418 NULL, /* GDBusAuthObserver */
419 NULL, /* GCancellable */
420 error);
423 out:
424 return c;
427 /* ---------------------------------------------------------------------------------------------------- */
429 static GPtrArray *
430 call_helper_get_method_in_signature (GDBusConnection *c,
431 const gchar *dest,
432 const gchar *path,
433 const gchar *interface_name,
434 const gchar *method_name,
435 GError **error)
437 GPtrArray *ret;
438 GVariant *result;
439 GDBusNodeInfo *node_info;
440 const gchar *xml_data;
441 GDBusInterfaceInfo *interface_info;
442 GDBusMethodInfo *method_info;
443 guint n;
445 ret = NULL;
446 result = NULL;
447 node_info = NULL;
449 result = g_dbus_connection_call_sync (c,
450 dest,
451 path,
452 "org.freedesktop.DBus.Introspectable",
453 "Introspect",
454 NULL,
455 G_VARIANT_TYPE ("(s)"),
456 G_DBUS_CALL_FLAGS_NONE,
457 3000, /* 3 secs */
458 NULL,
459 error);
460 if (result == NULL)
461 goto out;
463 g_variant_get (result, "(&s)", &xml_data);
464 node_info = g_dbus_node_info_new_for_xml (xml_data, error);
465 if (node_info == NULL)
466 goto out;
468 interface_info = g_dbus_node_info_lookup_interface (node_info, interface_name);
469 if (interface_info == NULL)
471 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
472 _("Warning: According to introspection data, interface “%s” does not exist\n"),
473 interface_name);
474 goto out;
477 method_info = g_dbus_interface_info_lookup_method (interface_info, method_name);
478 if (method_info == NULL)
480 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
481 _("Warning: According to introspection data, method “%s” does not exist on interface “%s”\n"),
482 method_name,
483 interface_name);
484 goto out;
487 ret = g_ptr_array_new_with_free_func ((GDestroyNotify) g_variant_type_free);
488 for (n = 0; method_info->in_args != NULL && method_info->in_args[n] != NULL; n++)
490 g_ptr_array_add (ret, g_variant_type_new (method_info->in_args[n]->signature));
493 out:
494 if (node_info != NULL)
495 g_dbus_node_info_unref (node_info);
496 if (result != NULL)
497 g_variant_unref (result);
499 return ret;
502 /* ---------------------------------------------------------------------------------------------------- */
504 static GVariant *
505 _g_variant_parse_me_harder (GVariantType *type,
506 const gchar *given_str,
507 GError **error)
509 GVariant *value;
510 gchar *s;
511 guint n;
512 GString *str;
514 str = g_string_new ("\"");
515 for (n = 0; given_str[n] != '\0'; n++)
517 if (G_UNLIKELY (given_str[n] == '\"'))
518 g_string_append (str, "\\\"");
519 else
520 g_string_append_c (str, given_str[n]);
522 g_string_append_c (str, '"');
523 s = g_string_free (str, FALSE);
525 value = g_variant_parse (type,
527 NULL,
528 NULL,
529 error);
530 g_free (s);
532 return value;
535 /* ---------------------------------------------------------------------------------------------------- */
537 static gchar *opt_emit_dest = NULL;
538 static gchar *opt_emit_object_path = NULL;
539 static gchar *opt_emit_signal = NULL;
541 static const GOptionEntry emit_entries[] =
543 { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_emit_dest, N_("Optional destination for signal (unique name)"), NULL},
544 { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_emit_object_path, N_("Object path to emit signal on"), NULL},
545 { "signal", 's', 0, G_OPTION_ARG_STRING, &opt_emit_signal, N_("Signal and interface name"), NULL},
546 { NULL }
549 static gboolean
550 handle_emit (gint *argc,
551 gchar **argv[],
552 gboolean request_completion,
553 const gchar *completion_cur,
554 const gchar *completion_prev)
556 gint ret;
557 GOptionContext *o;
558 gchar *s;
559 GError *error;
560 GDBusConnection *c;
561 GVariant *parameters;
562 gchar *interface_name;
563 gchar *signal_name;
564 GVariantBuilder builder;
565 gboolean skip_dashes;
566 guint parm;
567 guint n;
569 ret = FALSE;
570 c = NULL;
571 parameters = NULL;
572 interface_name = NULL;
573 signal_name = NULL;
575 modify_argv0_for_command (argc, argv, "emit");
577 o = g_option_context_new (NULL);
578 g_option_context_set_help_enabled (o, FALSE);
579 g_option_context_set_summary (o, _("Emit a signal."));
580 g_option_context_add_main_entries (o, emit_entries, GETTEXT_PACKAGE);
581 g_option_context_add_group (o, connection_get_group ());
583 if (!g_option_context_parse (o, argc, argv, NULL))
585 if (!request_completion)
587 s = g_option_context_get_help (o, FALSE, NULL);
588 g_printerr ("%s", s);
589 g_free (s);
590 goto out;
594 error = NULL;
595 c = connection_get_dbus_connection (&error);
596 if (c == NULL)
598 if (request_completion)
600 if (g_strcmp0 (completion_prev, "--address") == 0)
602 g_print ("unix:\n"
603 "tcp:\n"
604 "nonce-tcp:\n");
606 else
608 g_print ("--system \n--session \n--address \n");
611 else
613 g_printerr (_("Error connecting: %s\n"), error->message);
614 g_error_free (error);
616 goto out;
619 /* All done with completion now */
620 if (request_completion)
621 goto out;
623 if (opt_emit_object_path == NULL)
625 g_printerr (_("Error: object path not specified.\n"));
626 goto out;
628 if (!g_variant_is_object_path (opt_emit_object_path))
630 g_printerr (_("Error: %s is not a valid object path\n"), opt_emit_object_path);
631 goto out;
634 if (opt_emit_signal == NULL)
636 g_printerr (_("Error: signal not specified.\n"));
637 goto out;
640 s = strrchr (opt_emit_signal, '.');
641 if (s == NULL)
643 g_printerr (_("Error: signal must be the fully-qualified name.\n"));
644 goto out;
646 signal_name = g_strdup (s + 1);
647 interface_name = g_strndup (opt_emit_signal, s - opt_emit_signal);
649 if (!g_dbus_is_interface_name (interface_name))
651 g_printerr (_("Error: %s is not a valid interface name\n"), interface_name);
652 goto out;
655 if (!g_dbus_is_member_name (signal_name))
657 g_printerr (_("Error: %s is not a valid member name\n"), signal_name);
658 goto out;
661 if (opt_emit_dest != NULL && !g_dbus_is_unique_name (opt_emit_dest))
663 g_printerr (_("Error: %s is not a valid unique bus name.\n"), opt_emit_dest);
664 goto out;
667 /* Read parameters */
668 g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
669 skip_dashes = TRUE;
670 parm = 0;
671 for (n = 1; n < (guint) *argc; n++)
673 GVariant *value;
675 /* Under certain conditions, g_option_context_parse returns the "--"
676 itself (setting off unparsed arguments), too: */
677 if (skip_dashes && g_strcmp0 ((*argv)[n], "--") == 0)
679 skip_dashes = FALSE;
680 continue;
683 error = NULL;
684 value = g_variant_parse (NULL,
685 (*argv)[n],
686 NULL,
687 NULL,
688 &error);
689 if (value == NULL)
691 gchar *context;
693 context = g_variant_parse_error_print_context (error, (*argv)[n]);
694 g_error_free (error);
695 error = NULL;
696 value = _g_variant_parse_me_harder (NULL, (*argv)[n], &error);
697 if (value == NULL)
699 /* Use the original non-"parse-me-harder" error */
700 g_printerr (_("Error parsing parameter %d: %s\n"),
701 parm + 1,
702 context);
703 g_error_free (error);
704 g_free (context);
705 g_variant_builder_clear (&builder);
706 goto out;
708 g_free (context);
710 g_variant_builder_add_value (&builder, value);
711 ++parm;
713 parameters = g_variant_builder_end (&builder);
715 if (parameters != NULL)
716 parameters = g_variant_ref_sink (parameters);
717 if (!g_dbus_connection_emit_signal (c,
718 opt_emit_dest,
719 opt_emit_object_path,
720 interface_name,
721 signal_name,
722 parameters,
723 &error))
725 g_printerr (_("Error: %s\n"), error->message);
726 g_error_free (error);
727 goto out;
730 if (!g_dbus_connection_flush_sync (c, NULL, &error))
732 g_printerr (_("Error flushing connection: %s\n"), error->message);
733 g_error_free (error);
734 goto out;
737 ret = TRUE;
739 out:
740 if (c != NULL)
741 g_object_unref (c);
742 if (parameters != NULL)
743 g_variant_unref (parameters);
744 g_free (interface_name);
745 g_free (signal_name);
746 g_option_context_free (o);
747 return ret;
750 /* ---------------------------------------------------------------------------------------------------- */
752 static gchar *opt_call_dest = NULL;
753 static gchar *opt_call_object_path = NULL;
754 static gchar *opt_call_method = NULL;
755 static gint opt_call_timeout = -1;
757 static const GOptionEntry call_entries[] =
759 { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_call_dest, N_("Destination name to invoke method on"), NULL},
760 { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_call_object_path, N_("Object path to invoke method on"), NULL},
761 { "method", 'm', 0, G_OPTION_ARG_STRING, &opt_call_method, N_("Method and interface name"), NULL},
762 { "timeout", 't', 0, G_OPTION_ARG_INT, &opt_call_timeout, N_("Timeout in seconds"), NULL},
763 { NULL }
766 static gboolean
767 handle_call (gint *argc,
768 gchar **argv[],
769 gboolean request_completion,
770 const gchar *completion_cur,
771 const gchar *completion_prev)
773 gint ret;
774 GOptionContext *o;
775 gchar *s;
776 GError *error;
777 GDBusConnection *c;
778 GVariant *parameters;
779 gchar *interface_name;
780 gchar *method_name;
781 GVariant *result;
782 GPtrArray *in_signature_types;
783 gboolean complete_names;
784 gboolean complete_paths;
785 gboolean complete_methods;
786 GVariantBuilder builder;
787 gboolean skip_dashes;
788 guint parm;
789 guint n;
791 ret = FALSE;
792 c = NULL;
793 parameters = NULL;
794 interface_name = NULL;
795 method_name = NULL;
796 result = NULL;
797 in_signature_types = NULL;
799 modify_argv0_for_command (argc, argv, "call");
801 o = g_option_context_new (NULL);
802 g_option_context_set_help_enabled (o, FALSE);
803 g_option_context_set_summary (o, _("Invoke a method on a remote object."));
804 g_option_context_add_main_entries (o, call_entries, GETTEXT_PACKAGE);
805 g_option_context_add_group (o, connection_get_group ());
807 complete_names = FALSE;
808 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
810 complete_names = TRUE;
811 remove_arg ((*argc) - 1, argc, argv);
814 complete_paths = FALSE;
815 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
817 complete_paths = TRUE;
818 remove_arg ((*argc) - 1, argc, argv);
821 complete_methods = FALSE;
822 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--method") == 0)
824 complete_methods = TRUE;
825 remove_arg ((*argc) - 1, argc, argv);
828 if (!g_option_context_parse (o, argc, argv, NULL))
830 if (!request_completion)
832 s = g_option_context_get_help (o, FALSE, NULL);
833 g_printerr ("%s", s);
834 g_free (s);
835 goto out;
839 error = NULL;
840 c = connection_get_dbus_connection (&error);
841 if (c == NULL)
843 if (request_completion)
845 if (g_strcmp0 (completion_prev, "--address") == 0)
847 g_print ("unix:\n"
848 "tcp:\n"
849 "nonce-tcp:\n");
851 else
853 g_print ("--system \n--session \n--address \n");
856 else
858 g_printerr (_("Error connecting: %s\n"), error->message);
859 g_error_free (error);
861 goto out;
864 /* validate and complete destination (bus name) */
865 if (g_dbus_connection_get_unique_name (c) != NULL)
867 /* this only makes sense on message bus connections */
868 if (complete_names)
870 print_names (c, FALSE);
871 goto out;
873 if (opt_call_dest == NULL)
875 if (request_completion)
876 g_print ("--dest \n");
877 else
878 g_printerr (_("Error: Destination is not specified\n"));
879 goto out;
881 if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
883 print_names (c, g_str_has_prefix (opt_call_dest, ":"));
884 goto out;
888 if (!request_completion && !g_dbus_is_name (opt_call_dest))
890 g_printerr (_("Error: %s is not a valid bus name\n"), opt_call_dest);
891 goto out;
894 /* validate and complete object path */
895 if (complete_paths)
897 print_paths (c, opt_call_dest, "/");
898 goto out;
900 if (opt_call_object_path == NULL)
902 if (request_completion)
903 g_print ("--object-path \n");
904 else
905 g_printerr (_("Error: Object path is not specified\n"));
906 goto out;
908 if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
910 gchar *p;
911 s = g_strdup (opt_call_object_path);
912 p = strrchr (s, '/');
913 if (p != NULL)
915 if (p == s)
916 p++;
917 *p = '\0';
919 print_paths (c, opt_call_dest, s);
920 g_free (s);
921 goto out;
923 if (!request_completion && !g_variant_is_object_path (opt_call_object_path))
925 g_printerr (_("Error: %s is not a valid object path\n"), opt_call_object_path);
926 goto out;
929 /* validate and complete method (interface + method name) */
930 if (complete_methods)
932 print_methods (c, opt_call_dest, opt_call_object_path);
933 goto out;
935 if (opt_call_method == NULL)
937 if (request_completion)
938 g_print ("--method \n");
939 else
940 g_printerr (_("Error: Method name is not specified\n"));
941 goto out;
943 if (request_completion && g_strcmp0 ("--method", completion_prev) == 0)
945 print_methods (c, opt_call_dest, opt_call_object_path);
946 goto out;
948 s = strrchr (opt_call_method, '.');
949 if (!request_completion && s == NULL)
951 g_printerr (_("Error: Method name “%s” is invalid\n"), opt_call_method);
952 goto out;
954 method_name = g_strdup (s + 1);
955 interface_name = g_strndup (opt_call_method, s - opt_call_method);
957 /* All done with completion now */
958 if (request_completion)
959 goto out;
961 /* Introspect, for easy conversion - it's not fatal if we can't do this */
962 in_signature_types = call_helper_get_method_in_signature (c,
963 opt_call_dest,
964 opt_call_object_path,
965 interface_name,
966 method_name,
967 &error);
968 if (in_signature_types == NULL)
970 //g_printerr ("Error getting introspection data: %s\n", error->message);
971 g_error_free (error);
972 error = NULL;
975 /* Read parameters */
976 g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
977 skip_dashes = TRUE;
978 parm = 0;
979 for (n = 1; n < (guint) *argc; n++)
981 GVariant *value;
982 GVariantType *type;
984 /* Under certain conditions, g_option_context_parse returns the "--"
985 itself (setting off unparsed arguments), too: */
986 if (skip_dashes && g_strcmp0 ((*argv)[n], "--") == 0)
988 skip_dashes = FALSE;
989 continue;
992 type = NULL;
993 if (in_signature_types != NULL)
995 if (parm >= in_signature_types->len)
997 /* Only warn for the first param */
998 if (parm == in_signature_types->len)
1000 g_printerr ("Warning: Introspection data indicates %d parameters but more was passed\n",
1001 in_signature_types->len);
1004 else
1006 type = in_signature_types->pdata[parm];
1010 error = NULL;
1011 value = g_variant_parse (type,
1012 (*argv)[n],
1013 NULL,
1014 NULL,
1015 &error);
1016 if (value == NULL)
1018 gchar *context;
1020 context = g_variant_parse_error_print_context (error, (*argv)[n]);
1021 g_error_free (error);
1022 error = NULL;
1023 value = _g_variant_parse_me_harder (type, (*argv)[n], &error);
1024 if (value == NULL)
1026 if (type != NULL)
1028 s = g_variant_type_dup_string (type);
1029 g_printerr (_("Error parsing parameter %d of type “%s”: %s\n"),
1030 parm + 1,
1032 context);
1033 g_free (s);
1035 else
1037 g_printerr (_("Error parsing parameter %d: %s\n"),
1038 parm + 1,
1039 context);
1041 g_error_free (error);
1042 g_variant_builder_clear (&builder);
1043 g_free (context);
1044 goto out;
1046 g_free (context);
1048 g_variant_builder_add_value (&builder, value);
1049 ++parm;
1051 parameters = g_variant_builder_end (&builder);
1053 if (parameters != NULL)
1054 parameters = g_variant_ref_sink (parameters);
1055 result = g_dbus_connection_call_sync (c,
1056 opt_call_dest,
1057 opt_call_object_path,
1058 interface_name,
1059 method_name,
1060 parameters,
1061 NULL,
1062 G_DBUS_CALL_FLAGS_NONE,
1063 opt_call_timeout > 0 ? opt_call_timeout * 1000 : opt_call_timeout,
1064 NULL,
1065 &error);
1066 if (result == NULL)
1068 g_printerr (_("Error: %s\n"), error->message);
1070 if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS) && in_signature_types != NULL)
1072 if (in_signature_types->len > 0)
1074 GString *s;
1075 s = g_string_new (NULL);
1077 for (n = 0; n < in_signature_types->len; n++)
1079 GVariantType *type = in_signature_types->pdata[n];
1080 g_string_append_len (s,
1081 g_variant_type_peek_string (type),
1082 g_variant_type_get_string_length (type));
1085 g_printerr ("(According to introspection data, you need to pass '%s')\n", s->str);
1086 g_string_free (s, TRUE);
1088 else
1089 g_printerr ("(According to introspection data, you need to pass no arguments)\n");
1092 g_error_free (error);
1093 goto out;
1096 s = g_variant_print (result, TRUE);
1097 g_print ("%s\n", s);
1098 g_free (s);
1100 ret = TRUE;
1102 out:
1103 if (in_signature_types != NULL)
1104 g_ptr_array_unref (in_signature_types);
1105 if (result != NULL)
1106 g_variant_unref (result);
1107 if (c != NULL)
1108 g_object_unref (c);
1109 if (parameters != NULL)
1110 g_variant_unref (parameters);
1111 g_free (interface_name);
1112 g_free (method_name);
1113 g_option_context_free (o);
1114 return ret;
1117 /* ---------------------------------------------------------------------------------------------------- */
1119 static gchar *opt_introspect_dest = NULL;
1120 static gchar *opt_introspect_object_path = NULL;
1121 static gboolean opt_introspect_xml = FALSE;
1122 static gboolean opt_introspect_recurse = FALSE;
1123 static gboolean opt_introspect_only_properties = FALSE;
1125 static void
1126 dump_annotation (const GDBusAnnotationInfo *o,
1127 guint indent,
1128 gboolean ignore_indent)
1130 guint n;
1131 g_print ("%*s@%s(\"%s\")\n",
1132 ignore_indent ? 0 : indent, "",
1133 o->key,
1134 o->value);
1135 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1136 dump_annotation (o->annotations[n], indent + 2, FALSE);
1139 static void
1140 dump_arg (const GDBusArgInfo *o,
1141 guint indent,
1142 const gchar *direction,
1143 gboolean ignore_indent,
1144 gboolean include_newline)
1146 guint n;
1148 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1150 dump_annotation (o->annotations[n], indent, ignore_indent);
1151 ignore_indent = FALSE;
1154 g_print ("%*s%s%s %s%s",
1155 ignore_indent ? 0 : indent, "",
1156 direction,
1157 o->signature,
1158 o->name,
1159 include_newline ? ",\n" : "");
1162 static guint
1163 count_args (GDBusArgInfo **args)
1165 guint n;
1166 n = 0;
1167 if (args == NULL)
1168 goto out;
1169 while (args[n] != NULL)
1170 n++;
1171 out:
1172 return n;
1175 static void
1176 dump_method (const GDBusMethodInfo *o,
1177 guint indent)
1179 guint n;
1180 guint m;
1181 guint name_len;
1182 guint total_num_args;
1184 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1185 dump_annotation (o->annotations[n], indent, FALSE);
1187 g_print ("%*s%s(", indent, "", o->name);
1188 name_len = strlen (o->name);
1189 total_num_args = count_args (o->in_args) + count_args (o->out_args);
1190 for (n = 0, m = 0; o->in_args != NULL && o->in_args[n] != NULL; n++, m++)
1192 gboolean ignore_indent = (m == 0);
1193 gboolean include_newline = (m != total_num_args - 1);
1195 dump_arg (o->in_args[n],
1196 indent + name_len + 1,
1197 "in ",
1198 ignore_indent,
1199 include_newline);
1201 for (n = 0; o->out_args != NULL && o->out_args[n] != NULL; n++, m++)
1203 gboolean ignore_indent = (m == 0);
1204 gboolean include_newline = (m != total_num_args - 1);
1205 dump_arg (o->out_args[n],
1206 indent + name_len + 1,
1207 "out ",
1208 ignore_indent,
1209 include_newline);
1211 g_print (");\n");
1214 static void
1215 dump_signal (const GDBusSignalInfo *o,
1216 guint indent)
1218 guint n;
1219 guint name_len;
1220 guint total_num_args;
1222 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1223 dump_annotation (o->annotations[n], indent, FALSE);
1225 g_print ("%*s%s(", indent, "", o->name);
1226 name_len = strlen (o->name);
1227 total_num_args = count_args (o->args);
1228 for (n = 0; o->args != NULL && o->args[n] != NULL; n++)
1230 gboolean ignore_indent = (n == 0);
1231 gboolean include_newline = (n != total_num_args - 1);
1232 dump_arg (o->args[n],
1233 indent + name_len + 1,
1235 ignore_indent,
1236 include_newline);
1238 g_print (");\n");
1241 static void
1242 dump_property (const GDBusPropertyInfo *o,
1243 guint indent,
1244 GVariant *value)
1246 const gchar *access;
1247 guint n;
1249 if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
1250 access = "readonly";
1251 else if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)
1252 access = "writeonly";
1253 else if (o->flags == (G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE))
1254 access = "readwrite";
1255 else
1256 g_assert_not_reached ();
1258 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1259 dump_annotation (o->annotations[n], indent, FALSE);
1261 if (value != NULL)
1263 gchar *s = g_variant_print (value, FALSE);
1264 g_print ("%*s%s %s %s = %s;\n", indent, "", access, o->signature, o->name, s);
1265 g_free (s);
1267 else
1269 g_print ("%*s%s %s %s;\n", indent, "", access, o->signature, o->name);
1273 static void
1274 dump_interface (GDBusConnection *c,
1275 const gchar *name,
1276 const GDBusInterfaceInfo *o,
1277 guint indent,
1278 const gchar *object_path)
1280 guint n;
1281 GHashTable *properties;
1283 properties = g_hash_table_new_full (g_str_hash,
1284 g_str_equal,
1285 g_free,
1286 (GDestroyNotify) g_variant_unref);
1288 /* Try to get properties */
1289 if (c != NULL && name != NULL && object_path != NULL && o->properties != NULL)
1291 GVariant *result;
1292 result = g_dbus_connection_call_sync (c,
1293 name,
1294 object_path,
1295 "org.freedesktop.DBus.Properties",
1296 "GetAll",
1297 g_variant_new ("(s)", o->name),
1298 NULL,
1299 G_DBUS_CALL_FLAGS_NONE,
1300 3000,
1301 NULL,
1302 NULL);
1303 if (result != NULL)
1305 if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(a{sv})")))
1307 GVariantIter *iter;
1308 GVariant *item;
1309 g_variant_get (result,
1310 "(a{sv})",
1311 &iter);
1312 while ((item = g_variant_iter_next_value (iter)))
1314 gchar *key;
1315 GVariant *value;
1316 g_variant_get (item,
1317 "{sv}",
1318 &key,
1319 &value);
1321 g_hash_table_insert (properties, key, g_variant_ref (value));
1324 g_variant_unref (result);
1326 else
1328 guint n;
1329 for (n = 0; o->properties != NULL && o->properties[n] != NULL; n++)
1331 result = g_dbus_connection_call_sync (c,
1332 name,
1333 object_path,
1334 "org.freedesktop.DBus.Properties",
1335 "Get",
1336 g_variant_new ("(ss)", o->name, o->properties[n]->name),
1337 G_VARIANT_TYPE ("(v)"),
1338 G_DBUS_CALL_FLAGS_NONE,
1339 3000,
1340 NULL,
1341 NULL);
1342 if (result != NULL)
1344 GVariant *property_value;
1345 g_variant_get (result,
1346 "(v)",
1347 &property_value);
1348 g_hash_table_insert (properties,
1349 g_strdup (o->properties[n]->name),
1350 g_variant_ref (property_value));
1351 g_variant_unref (result);
1357 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1358 dump_annotation (o->annotations[n], indent, FALSE);
1360 g_print ("%*sinterface %s {\n", indent, "", o->name);
1361 if (o->methods != NULL && !opt_introspect_only_properties)
1363 g_print ("%*s methods:\n", indent, "");
1364 for (n = 0; o->methods[n] != NULL; n++)
1365 dump_method (o->methods[n], indent + 4);
1367 if (o->signals != NULL && !opt_introspect_only_properties)
1369 g_print ("%*s signals:\n", indent, "");
1370 for (n = 0; o->signals[n] != NULL; n++)
1371 dump_signal (o->signals[n], indent + 4);
1373 if (o->properties != NULL)
1375 g_print ("%*s properties:\n", indent, "");
1376 for (n = 0; o->properties[n] != NULL; n++)
1378 dump_property (o->properties[n],
1379 indent + 4,
1380 g_hash_table_lookup (properties, (o->properties[n])->name));
1383 g_print ("%*s};\n",
1384 indent, "");
1386 g_hash_table_unref (properties);
1389 static gboolean
1390 introspect_do (GDBusConnection *c,
1391 const gchar *object_path,
1392 guint indent);
1394 static void
1395 dump_node (GDBusConnection *c,
1396 const gchar *name,
1397 const GDBusNodeInfo *o,
1398 guint indent,
1399 const gchar *object_path,
1400 gboolean recurse)
1402 guint n;
1403 const gchar *object_path_to_print;
1405 object_path_to_print = object_path;
1406 if (o->path != NULL)
1407 object_path_to_print = o->path;
1409 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1410 dump_annotation (o->annotations[n], indent, FALSE);
1412 g_print ("%*snode %s", indent, "", object_path_to_print != NULL ? object_path_to_print : "(not set)");
1413 if (o->interfaces != NULL || o->nodes != NULL)
1415 g_print (" {\n");
1416 for (n = 0; o->interfaces != NULL && o->interfaces[n] != NULL; n++)
1418 if (opt_introspect_only_properties)
1420 if (o->interfaces[n]->properties != NULL && o->interfaces[n]->properties[0] != NULL)
1421 dump_interface (c, name, o->interfaces[n], indent + 2, object_path);
1423 else
1425 dump_interface (c, name, o->interfaces[n], indent + 2, object_path);
1428 for (n = 0; o->nodes != NULL && o->nodes[n] != NULL; n++)
1430 if (recurse)
1432 gchar *child_path;
1433 if (g_variant_is_object_path (o->nodes[n]->path))
1435 child_path = g_strdup (o->nodes[n]->path);
1436 /* avoid infinite loops */
1437 if (g_str_has_prefix (child_path, object_path))
1439 introspect_do (c, child_path, indent + 2);
1441 else
1443 g_print ("Skipping path %s that is not enclosed by parent %s\n",
1444 child_path, object_path);
1447 else
1449 if (g_strcmp0 (object_path, "/") == 0)
1450 child_path = g_strdup_printf ("/%s", o->nodes[n]->path);
1451 else
1452 child_path = g_strdup_printf ("%s/%s", object_path, o->nodes[n]->path);
1453 introspect_do (c, child_path, indent + 2);
1455 g_free (child_path);
1457 else
1459 dump_node (NULL, NULL, o->nodes[n], indent + 2, NULL, recurse);
1462 g_print ("%*s};\n",
1463 indent, "");
1465 else
1467 g_print ("\n");
1471 static const GOptionEntry introspect_entries[] =
1473 { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_introspect_dest, N_("Destination name to introspect"), NULL},
1474 { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_introspect_object_path, N_("Object path to introspect"), NULL},
1475 { "xml", 'x', 0, G_OPTION_ARG_NONE, &opt_introspect_xml, N_("Print XML"), NULL},
1476 { "recurse", 'r', 0, G_OPTION_ARG_NONE, &opt_introspect_recurse, N_("Introspect children"), NULL},
1477 { "only-properties", 'p', 0, G_OPTION_ARG_NONE, &opt_introspect_only_properties, N_("Only print properties"), NULL},
1478 { NULL }
1481 static gboolean
1482 introspect_do (GDBusConnection *c,
1483 const gchar *object_path,
1484 guint indent)
1486 GError *error;
1487 GVariant *result;
1488 GDBusNodeInfo *node;
1489 gboolean ret;
1490 const gchar *xml_data;
1492 ret = FALSE;
1493 node = NULL;
1494 result = NULL;
1496 error = NULL;
1497 result = g_dbus_connection_call_sync (c,
1498 opt_introspect_dest,
1499 object_path,
1500 "org.freedesktop.DBus.Introspectable",
1501 "Introspect",
1502 NULL,
1503 G_VARIANT_TYPE ("(s)"),
1504 G_DBUS_CALL_FLAGS_NONE,
1505 3000, /* 3 sec */
1506 NULL,
1507 &error);
1508 if (result == NULL)
1510 g_printerr (_("Error: %s\n"), error->message);
1511 g_error_free (error);
1512 goto out;
1514 g_variant_get (result, "(&s)", &xml_data);
1516 if (opt_introspect_xml)
1518 g_print ("%s", xml_data);
1520 else
1522 error = NULL;
1523 node = g_dbus_node_info_new_for_xml (xml_data, &error);
1524 if (node == NULL)
1526 g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
1527 g_error_free (error);
1528 goto out;
1531 dump_node (c, opt_introspect_dest, node, indent, object_path, opt_introspect_recurse);
1534 ret = TRUE;
1536 out:
1537 if (node != NULL)
1538 g_dbus_node_info_unref (node);
1539 if (result != NULL)
1540 g_variant_unref (result);
1541 return ret;
1544 static gboolean
1545 handle_introspect (gint *argc,
1546 gchar **argv[],
1547 gboolean request_completion,
1548 const gchar *completion_cur,
1549 const gchar *completion_prev)
1551 gint ret;
1552 GOptionContext *o;
1553 gchar *s;
1554 GError *error;
1555 GDBusConnection *c;
1556 gboolean complete_names;
1557 gboolean complete_paths;
1559 ret = FALSE;
1560 c = NULL;
1562 modify_argv0_for_command (argc, argv, "introspect");
1564 o = g_option_context_new (NULL);
1565 if (request_completion)
1566 g_option_context_set_ignore_unknown_options (o, TRUE);
1567 g_option_context_set_help_enabled (o, FALSE);
1568 g_option_context_set_summary (o, _("Introspect a remote object."));
1569 g_option_context_add_main_entries (o, introspect_entries, GETTEXT_PACKAGE);
1570 g_option_context_add_group (o, connection_get_group ());
1572 complete_names = FALSE;
1573 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
1575 complete_names = TRUE;
1576 remove_arg ((*argc) - 1, argc, argv);
1579 complete_paths = FALSE;
1580 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
1582 complete_paths = TRUE;
1583 remove_arg ((*argc) - 1, argc, argv);
1586 if (!g_option_context_parse (o, argc, argv, NULL))
1588 if (!request_completion)
1590 s = g_option_context_get_help (o, FALSE, NULL);
1591 g_printerr ("%s", s);
1592 g_free (s);
1593 goto out;
1597 error = NULL;
1598 c = connection_get_dbus_connection (&error);
1599 if (c == NULL)
1601 if (request_completion)
1603 if (g_strcmp0 (completion_prev, "--address") == 0)
1605 g_print ("unix:\n"
1606 "tcp:\n"
1607 "nonce-tcp:\n");
1609 else
1611 g_print ("--system \n--session \n--address \n");
1614 else
1616 g_printerr (_("Error connecting: %s\n"), error->message);
1617 g_error_free (error);
1619 goto out;
1622 if (g_dbus_connection_get_unique_name (c) != NULL)
1624 if (complete_names)
1626 print_names (c, FALSE);
1627 goto out;
1629 /* this only makes sense on message bus connections */
1630 if (opt_introspect_dest == NULL)
1632 if (request_completion)
1633 g_print ("--dest \n");
1634 else
1635 g_printerr (_("Error: Destination is not specified\n"));
1636 goto out;
1638 if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
1640 print_names (c, g_str_has_prefix (opt_introspect_dest, ":"));
1641 goto out;
1644 if (complete_paths)
1646 print_paths (c, opt_introspect_dest, "/");
1647 goto out;
1650 if (!request_completion && !g_dbus_is_name (opt_introspect_dest))
1652 g_printerr (_("Error: %s is not a valid bus name\n"), opt_introspect_dest);
1653 goto out;
1656 if (opt_introspect_object_path == NULL)
1658 if (request_completion)
1659 g_print ("--object-path \n");
1660 else
1661 g_printerr (_("Error: Object path is not specified\n"));
1662 goto out;
1664 if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
1666 gchar *p;
1667 s = g_strdup (opt_introspect_object_path);
1668 p = strrchr (s, '/');
1669 if (p != NULL)
1671 if (p == s)
1672 p++;
1673 *p = '\0';
1675 print_paths (c, opt_introspect_dest, s);
1676 g_free (s);
1677 goto out;
1679 if (!request_completion && !g_variant_is_object_path (opt_introspect_object_path))
1681 g_printerr (_("Error: %s is not a valid object path\n"), opt_introspect_object_path);
1682 goto out;
1685 if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_recurse)
1687 g_print ("--recurse \n");
1690 if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_only_properties)
1692 g_print ("--only-properties \n");
1695 /* All done with completion now */
1696 if (request_completion)
1697 goto out;
1699 if (!introspect_do (c, opt_introspect_object_path, 0))
1700 goto out;
1702 ret = TRUE;
1704 out:
1705 if (c != NULL)
1706 g_object_unref (c);
1707 g_option_context_free (o);
1708 return ret;
1711 /* ---------------------------------------------------------------------------------------------------- */
1713 static gchar *opt_monitor_dest = NULL;
1714 static gchar *opt_monitor_object_path = NULL;
1716 static guint monitor_filter_id = 0;
1718 static void
1719 monitor_signal_cb (GDBusConnection *connection,
1720 const gchar *sender_name,
1721 const gchar *object_path,
1722 const gchar *interface_name,
1723 const gchar *signal_name,
1724 GVariant *parameters,
1725 gpointer user_data)
1727 gchar *s;
1728 s = g_variant_print (parameters, TRUE);
1729 g_print ("%s: %s.%s %s\n",
1730 object_path,
1731 interface_name,
1732 signal_name,
1734 g_free (s);
1737 static void
1738 monitor_on_name_appeared (GDBusConnection *connection,
1739 const gchar *name,
1740 const gchar *name_owner,
1741 gpointer user_data)
1743 g_print ("The name %s is owned by %s\n", name, name_owner);
1744 g_assert (monitor_filter_id == 0);
1745 monitor_filter_id = g_dbus_connection_signal_subscribe (connection,
1746 name_owner,
1747 NULL, /* any interface */
1748 NULL, /* any member */
1749 opt_monitor_object_path,
1750 NULL, /* arg0 */
1751 G_DBUS_SIGNAL_FLAGS_NONE,
1752 monitor_signal_cb,
1753 NULL, /* user_data */
1754 NULL); /* user_data destroy notify */
1757 static void
1758 monitor_on_name_vanished (GDBusConnection *connection,
1759 const gchar *name,
1760 gpointer user_data)
1762 g_print ("The name %s does not have an owner\n", name);
1764 if (monitor_filter_id != 0)
1766 g_dbus_connection_signal_unsubscribe (connection, monitor_filter_id);
1767 monitor_filter_id = 0;
1771 static const GOptionEntry monitor_entries[] =
1773 { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_monitor_dest, N_("Destination name to monitor"), NULL},
1774 { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_monitor_object_path, N_("Object path to monitor"), NULL},
1775 { NULL }
1778 static gboolean
1779 handle_monitor (gint *argc,
1780 gchar **argv[],
1781 gboolean request_completion,
1782 const gchar *completion_cur,
1783 const gchar *completion_prev)
1785 gint ret;
1786 GOptionContext *o;
1787 gchar *s;
1788 GError *error;
1789 GDBusConnection *c;
1790 gboolean complete_names;
1791 gboolean complete_paths;
1792 GMainLoop *loop;
1794 ret = FALSE;
1795 c = NULL;
1797 modify_argv0_for_command (argc, argv, "monitor");
1799 o = g_option_context_new (NULL);
1800 if (request_completion)
1801 g_option_context_set_ignore_unknown_options (o, TRUE);
1802 g_option_context_set_help_enabled (o, FALSE);
1803 g_option_context_set_summary (o, _("Monitor a remote object."));
1804 g_option_context_add_main_entries (o, monitor_entries, GETTEXT_PACKAGE);
1805 g_option_context_add_group (o, connection_get_group ());
1807 complete_names = FALSE;
1808 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
1810 complete_names = TRUE;
1811 remove_arg ((*argc) - 1, argc, argv);
1814 complete_paths = FALSE;
1815 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
1817 complete_paths = TRUE;
1818 remove_arg ((*argc) - 1, argc, argv);
1821 if (!g_option_context_parse (o, argc, argv, NULL))
1823 if (!request_completion)
1825 s = g_option_context_get_help (o, FALSE, NULL);
1826 g_printerr ("%s", s);
1827 g_free (s);
1828 goto out;
1832 error = NULL;
1833 c = connection_get_dbus_connection (&error);
1834 if (c == NULL)
1836 if (request_completion)
1838 if (g_strcmp0 (completion_prev, "--address") == 0)
1840 g_print ("unix:\n"
1841 "tcp:\n"
1842 "nonce-tcp:\n");
1844 else
1846 g_print ("--system \n--session \n--address \n");
1849 else
1851 g_printerr (_("Error connecting: %s\n"), error->message);
1852 g_error_free (error);
1854 goto out;
1857 if (g_dbus_connection_get_unique_name (c) != NULL)
1859 if (complete_names)
1861 print_names (c, FALSE);
1862 goto out;
1864 /* this only makes sense on message bus connections */
1865 if (opt_monitor_dest == NULL)
1867 if (request_completion)
1868 g_print ("--dest \n");
1869 else
1870 g_printerr (_("Error: Destination is not specified\n"));
1871 goto out;
1873 if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
1875 print_names (c, g_str_has_prefix (opt_monitor_dest, ":"));
1876 goto out;
1880 if (!request_completion && !g_dbus_is_name (opt_monitor_dest))
1882 g_printerr (_("Error: %s is not a valid bus name\n"), opt_monitor_dest);
1883 goto out;
1886 if (complete_paths)
1888 print_paths (c, opt_monitor_dest, "/");
1889 goto out;
1891 if (opt_monitor_object_path == NULL)
1893 if (request_completion)
1895 g_print ("--object-path \n");
1896 goto out;
1898 /* it's fine to not have an object path */
1900 if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
1902 gchar *p;
1903 s = g_strdup (opt_monitor_object_path);
1904 p = strrchr (s, '/');
1905 if (p != NULL)
1907 if (p == s)
1908 p++;
1909 *p = '\0';
1911 print_paths (c, opt_monitor_dest, s);
1912 g_free (s);
1913 goto out;
1915 if (!request_completion && (opt_monitor_object_path != NULL && !g_variant_is_object_path (opt_monitor_object_path)))
1917 g_printerr (_("Error: %s is not a valid object path\n"), opt_monitor_object_path);
1918 goto out;
1921 /* All done with completion now */
1922 if (request_completion)
1923 goto out;
1925 if (opt_monitor_object_path != NULL)
1926 g_print ("Monitoring signals on object %s owned by %s\n", opt_monitor_object_path, opt_monitor_dest);
1927 else
1928 g_print ("Monitoring signals from all objects owned by %s\n", opt_monitor_dest);
1930 loop = g_main_loop_new (NULL, FALSE);
1931 g_bus_watch_name_on_connection (c,
1932 opt_monitor_dest,
1933 G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
1934 monitor_on_name_appeared,
1935 monitor_on_name_vanished,
1936 NULL,
1937 NULL);
1939 g_main_loop_run (loop);
1940 g_main_loop_unref (loop);
1942 ret = TRUE;
1944 out:
1945 if (c != NULL)
1946 g_object_unref (c);
1947 g_option_context_free (o);
1948 return ret;
1951 /* ---------------------------------------------------------------------------------------------------- */
1953 static gboolean opt_wait_activate_set = FALSE;
1954 static gchar *opt_wait_activate_name = NULL;
1955 static gint64 opt_wait_timeout = 0; /* no timeout */
1957 typedef enum {
1958 WAIT_STATE_RUNNING, /* waiting to see the service */
1959 WAIT_STATE_SUCCESS, /* seen it successfully */
1960 WAIT_STATE_TIMEOUT, /* timed out before seeing it */
1961 } WaitState;
1963 static gboolean
1964 opt_wait_activate_cb (const gchar *option_name,
1965 const gchar *value,
1966 gpointer data,
1967 GError **error)
1969 /* @value may be NULL */
1970 opt_wait_activate_set = TRUE;
1971 opt_wait_activate_name = g_strdup (value);
1973 return TRUE;
1976 static const GOptionEntry wait_entries[] =
1978 { "activate", 'a', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
1979 opt_wait_activate_cb,
1980 N_("Service to activate before waiting for the other one (well-known name)"),
1981 "[NAME]" },
1982 { "timeout", 't', 0, G_OPTION_ARG_INT64, &opt_wait_timeout,
1983 N_("Timeout to wait for before exiting with an error (seconds); 0 for "
1984 "no timeout (default)"), "SECS" },
1985 { NULL }
1988 static void
1989 wait_name_appeared_cb (GDBusConnection *connection,
1990 const gchar *name,
1991 const gchar *name_owner,
1992 gpointer user_data)
1994 WaitState *wait_state = user_data;
1996 *wait_state = WAIT_STATE_SUCCESS;
1999 static gboolean
2000 wait_timeout_cb (gpointer user_data)
2002 WaitState *wait_state = user_data;
2004 *wait_state = WAIT_STATE_TIMEOUT;
2006 /* Removed in handle_wait(). */
2007 return G_SOURCE_CONTINUE;
2010 static gboolean
2011 handle_wait (gint *argc,
2012 gchar **argv[],
2013 gboolean request_completion,
2014 const gchar *completion_cur,
2015 const gchar *completion_prev)
2017 gint ret;
2018 GOptionContext *o;
2019 gchar *s;
2020 GError *error;
2021 GDBusConnection *c;
2022 guint watch_id, timer_id = 0, activate_watch_id;
2023 const gchar *activate_service, *wait_service;
2024 WaitState wait_state = WAIT_STATE_RUNNING;
2026 ret = FALSE;
2027 c = NULL;
2029 modify_argv0_for_command (argc, argv, "wait");
2031 o = g_option_context_new (_("[OPTION…] BUS-NAME"));
2032 g_option_context_set_help_enabled (o, FALSE);
2033 g_option_context_set_summary (o, _("Wait for a bus name to appear."));
2034 g_option_context_add_main_entries (o, wait_entries, GETTEXT_PACKAGE);
2035 g_option_context_add_group (o, connection_get_group ());
2037 if (!g_option_context_parse (o, argc, argv, NULL))
2039 if (!request_completion)
2041 s = g_option_context_get_help (o, FALSE, NULL);
2042 g_printerr ("%s", s);
2043 g_free (s);
2044 goto out;
2048 error = NULL;
2049 c = connection_get_dbus_connection (&error);
2050 if (c == NULL)
2052 if (request_completion)
2054 if (g_strcmp0 (completion_prev, "--address") == 0)
2056 g_print ("unix:\n"
2057 "tcp:\n"
2058 "nonce-tcp:\n");
2060 else
2062 g_print ("--system \n--session \n--address \n");
2065 else
2067 g_printerr (_("Error connecting: %s\n"), error->message);
2068 g_error_free (error);
2070 goto out;
2073 /* All done with completion now */
2074 if (request_completion)
2075 goto out;
2078 * Try and disentangle the command line arguments, with the aim of supporting:
2079 * gdbus wait --session --activate ActivateName WaitName
2080 * gdbus wait --session --activate ActivateAndWaitName
2081 * gdbus wait --activate --session ActivateAndWaitName
2082 * gdbus wait --session WaitName
2084 if (*argc == 2 && opt_wait_activate_set && opt_wait_activate_name != NULL)
2086 activate_service = opt_wait_activate_name;
2087 wait_service = (*argv)[1];
2089 else if (*argc == 2 &&
2090 opt_wait_activate_set && opt_wait_activate_name == NULL)
2092 activate_service = (*argv)[1];
2093 wait_service = (*argv)[1];
2095 else if (*argc == 2 && !opt_wait_activate_set)
2097 activate_service = NULL; /* disabled */
2098 wait_service = (*argv)[1];
2100 else if (*argc == 1 &&
2101 opt_wait_activate_set && opt_wait_activate_name != NULL)
2103 activate_service = opt_wait_activate_name;
2104 wait_service = opt_wait_activate_name;
2106 else if (*argc == 1 &&
2107 opt_wait_activate_set && opt_wait_activate_name == NULL)
2109 g_printerr (_("Error: A service to activate for must be specified.\n"));
2110 goto out;
2112 else if (*argc == 1 && !opt_wait_activate_set)
2114 g_printerr (_("Error: A service to wait for must be specified.\n"));
2115 goto out;
2117 else /* if (*argc > 2) */
2119 g_printerr (_("Error: Too many arguments.\n"));
2120 goto out;
2123 if (activate_service != NULL &&
2124 (!g_dbus_is_name (activate_service) ||
2125 g_dbus_is_unique_name (activate_service)))
2127 g_printerr (_("Error: %s is not a valid well-known bus name.\n"),
2128 activate_service);
2129 goto out;
2132 if (!g_dbus_is_name (wait_service) || g_dbus_is_unique_name (wait_service))
2134 g_printerr (_("Error: %s is not a valid well-known bus name.\n"),
2135 wait_service);
2136 goto out;
2139 /* Start the prerequisite service if needed. */
2140 if (activate_service != NULL)
2142 activate_watch_id = g_bus_watch_name_on_connection (c, activate_service,
2143 G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
2144 NULL, NULL,
2145 NULL, NULL);
2147 else
2149 activate_watch_id = 0;
2152 /* Wait for the expected name to appear. */
2153 watch_id = g_bus_watch_name_on_connection (c,
2154 wait_service,
2155 G_BUS_NAME_WATCHER_FLAGS_NONE,
2156 wait_name_appeared_cb,
2157 NULL, &wait_state, NULL);
2159 /* Safety timeout. */
2160 if (opt_wait_timeout > 0)
2161 timer_id = g_timeout_add (opt_wait_timeout, wait_timeout_cb, &wait_state);
2163 while (wait_state == WAIT_STATE_RUNNING)
2164 g_main_context_iteration (NULL, TRUE);
2166 g_bus_unwatch_name (watch_id);
2167 if (timer_id != 0)
2168 g_source_remove (timer_id);
2169 if (activate_watch_id != 0)
2170 g_bus_unwatch_name (activate_watch_id);
2172 ret = (wait_state == WAIT_STATE_SUCCESS);
2174 out:
2175 g_clear_object (&c);
2176 g_option_context_free (o);
2177 g_free (opt_wait_activate_name);
2178 opt_wait_activate_name = NULL;
2180 return ret;
2183 /* ---------------------------------------------------------------------------------------------------- */
2185 static gchar *
2186 pick_word_at (const gchar *s,
2187 gint cursor,
2188 gint *out_word_begins_at)
2190 gint begin;
2191 gint end;
2193 if (s[0] == '\0')
2195 if (out_word_begins_at != NULL)
2196 *out_word_begins_at = -1;
2197 return NULL;
2200 if (g_ascii_isspace (s[cursor]) && ((cursor > 0 && g_ascii_isspace(s[cursor-1])) || cursor == 0))
2202 if (out_word_begins_at != NULL)
2203 *out_word_begins_at = cursor;
2204 return g_strdup ("");
2207 while (!g_ascii_isspace (s[cursor - 1]) && cursor > 0)
2208 cursor--;
2209 begin = cursor;
2211 end = begin;
2212 while (!g_ascii_isspace (s[end]) && s[end] != '\0')
2213 end++;
2215 if (out_word_begins_at != NULL)
2216 *out_word_begins_at = begin;
2218 return g_strndup (s + begin, end - begin);
2221 gint
2222 main (gint argc, gchar *argv[])
2224 gint ret;
2225 const gchar *command;
2226 gboolean request_completion;
2227 gchar *completion_cur;
2228 gchar *completion_prev;
2229 #ifdef G_OS_WIN32
2230 gchar *tmp;
2231 #endif
2233 setlocale (LC_ALL, "");
2234 textdomain (GETTEXT_PACKAGE);
2236 #ifdef G_OS_WIN32
2237 tmp = _glib_get_locale_dir ();
2238 bindtextdomain (GETTEXT_PACKAGE, tmp);
2239 g_free (tmp);
2240 #else
2241 bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
2242 #endif
2244 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
2245 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
2246 #endif
2248 ret = 1;
2249 completion_cur = NULL;
2250 completion_prev = NULL;
2252 if (argc < 2)
2254 usage (&argc, &argv, FALSE);
2255 goto out;
2258 request_completion = FALSE;
2260 //completion_debug ("---- argc=%d --------------------------------------------------------", argc);
2262 again:
2263 command = argv[1];
2264 if (g_strcmp0 (command, "help") == 0)
2266 if (request_completion)
2268 /* do nothing */
2270 else
2272 usage (&argc, &argv, TRUE);
2273 ret = 0;
2275 goto out;
2277 else if (g_strcmp0 (command, "emit") == 0)
2279 if (handle_emit (&argc,
2280 &argv,
2281 request_completion,
2282 completion_cur,
2283 completion_prev))
2284 ret = 0;
2285 goto out;
2287 else if (g_strcmp0 (command, "call") == 0)
2289 if (handle_call (&argc,
2290 &argv,
2291 request_completion,
2292 completion_cur,
2293 completion_prev))
2294 ret = 0;
2295 goto out;
2297 else if (g_strcmp0 (command, "introspect") == 0)
2299 if (handle_introspect (&argc,
2300 &argv,
2301 request_completion,
2302 completion_cur,
2303 completion_prev))
2304 ret = 0;
2305 goto out;
2307 else if (g_strcmp0 (command, "monitor") == 0)
2309 if (handle_monitor (&argc,
2310 &argv,
2311 request_completion,
2312 completion_cur,
2313 completion_prev))
2314 ret = 0;
2315 goto out;
2317 else if (g_strcmp0 (command, "wait") == 0)
2319 if (handle_wait (&argc,
2320 &argv,
2321 request_completion,
2322 completion_cur,
2323 completion_prev))
2324 ret = 0;
2325 goto out;
2327 else if (g_strcmp0 (command, "complete") == 0 && argc == 4 && !request_completion)
2329 const gchar *completion_line;
2330 gchar **completion_argv;
2331 gint completion_argc;
2332 gint completion_point;
2333 gchar *endp;
2334 gint cur_begin;
2336 request_completion = TRUE;
2338 completion_line = argv[2];
2339 completion_point = strtol (argv[3], &endp, 10);
2340 if (endp == argv[3] || *endp != '\0')
2341 goto out;
2343 #if 0
2344 completion_debug ("completion_point=%d", completion_point);
2345 completion_debug ("----");
2346 completion_debug (" 0123456789012345678901234567890123456789012345678901234567890123456789");
2347 completion_debug ("'%s'", completion_line);
2348 completion_debug (" %*s^",
2349 completion_point, "");
2350 completion_debug ("----");
2351 #endif
2353 if (!g_shell_parse_argv (completion_line,
2354 &completion_argc,
2355 &completion_argv,
2356 NULL))
2358 /* it's very possible the command line can't be parsed (for
2359 * example, missing quotes etc) - in that case, we just
2360 * don't autocomplete at all
2362 goto out;
2365 /* compute cur and prev */
2366 completion_prev = NULL;
2367 completion_cur = pick_word_at (completion_line, completion_point, &cur_begin);
2368 if (cur_begin > 0)
2370 gint prev_end;
2371 for (prev_end = cur_begin - 1; prev_end >= 0; prev_end--)
2373 if (!g_ascii_isspace (completion_line[prev_end]))
2375 completion_prev = pick_word_at (completion_line, prev_end, NULL);
2376 break;
2380 #if 0
2381 completion_debug (" cur='%s'", completion_cur);
2382 completion_debug ("prev='%s'", completion_prev);
2383 #endif
2385 argc = completion_argc;
2386 argv = completion_argv;
2388 ret = 0;
2390 goto again;
2392 else
2394 if (request_completion)
2396 g_print ("help \nemit \ncall \nintrospect \nmonitor \nwait \n");
2397 ret = 0;
2398 goto out;
2400 else
2402 g_printerr ("Unknown command '%s'\n", command);
2403 usage (&argc, &argv, FALSE);
2404 goto out;
2408 out:
2409 g_free (completion_cur);
2410 g_free (completion_prev);
2411 return ret;