mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-25 06:56:14 +01:00
gdbus-tool: Add a command to wait for a well-known name on the bus
This is effectively the mc-wait-for-name tool from telepathy-mission-control; moving it in to gdbus-tool will make it more widely useful without making people depend on telepathy-mission-control for no other reason. The code here is reimplemented from scratch to use GDBus. It blocks until the specified well-known name is owned by some process on the bus (which can be the session, system, or any other bus). By passing --activate, the same (or a different) name can be auto-started on the bus first. A timeout can be specified to ensure the process doesn’t block forever. https://bugzilla.gnome.org/show_bug.cgi?id=745971
This commit is contained in:
parent
ff7f32f643
commit
7890573f6e
@ -91,6 +91,20 @@
|
|||||||
<arg choice="plain">ARG1</arg>
|
<arg choice="plain">ARG1</arg>
|
||||||
<arg choice="plain" rep="repeat">ARG2</arg>
|
<arg choice="plain" rep="repeat">ARG2</arg>
|
||||||
</cmdsynopsis>
|
</cmdsynopsis>
|
||||||
|
<cmdsynopsis>
|
||||||
|
<command>gdbus</command>
|
||||||
|
<arg choice="plain">wait</arg>
|
||||||
|
<group>
|
||||||
|
<arg choice="plain">--system</arg>
|
||||||
|
<arg choice="plain">--session</arg>
|
||||||
|
<arg choice="plain">--address <replaceable>address</replaceable></arg>
|
||||||
|
</group>
|
||||||
|
<arg choice="plain">--activate <replaceable>bus_name</replaceable></arg>
|
||||||
|
<group>
|
||||||
|
<arg choice="plain">--timeout <replaceable>seconds</replaceable></arg>
|
||||||
|
</group>
|
||||||
|
<arg choice="plain"><replaceable>bus_name</replaceable></arg>
|
||||||
|
</cmdsynopsis>
|
||||||
<cmdsynopsis>
|
<cmdsynopsis>
|
||||||
<command>gdbus</command>
|
<command>gdbus</command>
|
||||||
<arg choice="plain">help</arg>
|
<arg choice="plain">help</arg>
|
||||||
@ -147,6 +161,15 @@
|
|||||||
not need explicit quotes.
|
not need explicit quotes.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>wait</option></term>
|
||||||
|
<listitem><para>
|
||||||
|
Waits until <replaceable>bus_name</replaceable> is owned by some
|
||||||
|
process on the bus. If the <option>--activate</option> is specified,
|
||||||
|
that bus name will be auto-started first. It may be the same as the
|
||||||
|
bus name being waited for, or different.
|
||||||
|
</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>help</option></term>
|
<term><option>help</option></term>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
@ -337,6 +360,38 @@ $ gdbus emit --session --object-path /foo --signal org.bar.Foo "['foo', 'bar', '
|
|||||||
$ gdbus emit --session --object-path /bar --signal org.bar.Bar someString --dest :1.42
|
$ gdbus emit --session --object-path /bar --signal org.bar.Bar someString --dest :1.42
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Waiting for a well-known name to be owned on the bus; this will
|
||||||
|
<emphasis>not</emphasis> auto-start the service:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
$ gdbus wait --session org.bar.SomeName
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Auto-starting then waiting for a well-known name to be owned on the bus:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
$ gdbus wait --session --activate org.bar.SomeName
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Auto-starting a different service, then waiting for a well-known name to be
|
||||||
|
owned on the bus. This is useful in situations where
|
||||||
|
<replaceable>SomeName</replaceable> is not directly activatable:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
$ gdbus wait --session --activate org.bar.PrerequisiteName org.bar.SomeName
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Waiting for a well-known name and giving up after 30 seconds. By default,
|
||||||
|
the timeout is disabled; or set <option>--timeout</option> to 0 to disable it:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
$ gdbus wait --session --timeout 30 org.bar.SomeName
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
|
249
gio/gdbus-tool.c
249
gio/gdbus-tool.c
@ -98,6 +98,7 @@ usage (gint *argc, gchar **argv[], gboolean use_stdout)
|
|||||||
" monitor Monitor a remote object\n"
|
" monitor Monitor a remote object\n"
|
||||||
" call Invoke a method on a remote object\n"
|
" call Invoke a method on a remote object\n"
|
||||||
" emit Emit a signal\n"
|
" emit Emit a signal\n"
|
||||||
|
" wait Wait for a bus name to appear\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Use “%s COMMAND --help” to get help on each command.\n"),
|
"Use “%s COMMAND --help” to get help on each command.\n"),
|
||||||
program_name);
|
program_name);
|
||||||
@ -1949,6 +1950,242 @@ handle_monitor (gint *argc,
|
|||||||
|
|
||||||
/* ---------------------------------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static gboolean opt_wait_activate_set = FALSE;
|
||||||
|
static gchar *opt_wait_activate_name = NULL;
|
||||||
|
static gint64 opt_wait_timeout = 0; /* no timeout */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
WAIT_STATE_RUNNING, /* waiting to see the service */
|
||||||
|
WAIT_STATE_SUCCESS, /* seen it successfully */
|
||||||
|
WAIT_STATE_TIMEOUT, /* timed out before seeing it */
|
||||||
|
} WaitState;
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
opt_wait_activate_cb (const gchar *option_name,
|
||||||
|
const gchar *value,
|
||||||
|
gpointer data,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
/* @value may be NULL */
|
||||||
|
opt_wait_activate_set = TRUE;
|
||||||
|
opt_wait_activate_name = g_strdup (value);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const GOptionEntry wait_entries[] =
|
||||||
|
{
|
||||||
|
{ "activate", 'a', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
|
||||||
|
opt_wait_activate_cb,
|
||||||
|
N_("Service to activate before waiting for the other one (well-known name)"),
|
||||||
|
"[NAME]" },
|
||||||
|
{ "timeout", 't', 0, G_OPTION_ARG_INT64, &opt_wait_timeout,
|
||||||
|
N_("Timeout to wait for before exiting with an error (seconds); 0 for "
|
||||||
|
"no timeout (default)"), "SECS" },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
wait_name_appeared_cb (GDBusConnection *connection,
|
||||||
|
const gchar *name,
|
||||||
|
const gchar *name_owner,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
WaitState *wait_state = user_data;
|
||||||
|
|
||||||
|
*wait_state = WAIT_STATE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
wait_timeout_cb (gpointer user_data)
|
||||||
|
{
|
||||||
|
WaitState *wait_state = user_data;
|
||||||
|
|
||||||
|
*wait_state = WAIT_STATE_TIMEOUT;
|
||||||
|
|
||||||
|
/* Removed in handle_wait(). */
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
handle_wait (gint *argc,
|
||||||
|
gchar **argv[],
|
||||||
|
gboolean request_completion,
|
||||||
|
const gchar *completion_cur,
|
||||||
|
const gchar *completion_prev)
|
||||||
|
{
|
||||||
|
gint ret;
|
||||||
|
GOptionContext *o;
|
||||||
|
gchar *s;
|
||||||
|
GError *error;
|
||||||
|
GDBusConnection *c;
|
||||||
|
guint watch_id, timer_id = 0, activate_watch_id;
|
||||||
|
const gchar *activate_service, *wait_service;
|
||||||
|
WaitState wait_state = WAIT_STATE_RUNNING;
|
||||||
|
|
||||||
|
ret = FALSE;
|
||||||
|
c = NULL;
|
||||||
|
|
||||||
|
modify_argv0_for_command (argc, argv, "wait");
|
||||||
|
|
||||||
|
o = g_option_context_new (NULL);
|
||||||
|
g_option_context_set_help_enabled (o, FALSE);
|
||||||
|
g_option_context_set_summary (o, _("Wait for a bus name to appear."));
|
||||||
|
g_option_context_add_main_entries (o, wait_entries, GETTEXT_PACKAGE);
|
||||||
|
g_option_context_add_group (o, connection_get_group ());
|
||||||
|
|
||||||
|
if (!g_option_context_parse (o, argc, argv, NULL))
|
||||||
|
{
|
||||||
|
if (!request_completion)
|
||||||
|
{
|
||||||
|
s = g_option_context_get_help (o, FALSE, NULL);
|
||||||
|
g_printerr ("%s", s);
|
||||||
|
g_free (s);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error = NULL;
|
||||||
|
c = connection_get_dbus_connection (&error);
|
||||||
|
if (c == NULL)
|
||||||
|
{
|
||||||
|
if (request_completion)
|
||||||
|
{
|
||||||
|
if (g_strcmp0 (completion_prev, "--address") == 0)
|
||||||
|
{
|
||||||
|
g_print ("unix:\n"
|
||||||
|
"tcp:\n"
|
||||||
|
"nonce-tcp:\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_print ("--system \n--session \n--address \n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_printerr (_("Error connecting: %s\n"), error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All done with completion now */
|
||||||
|
if (request_completion)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try and disentangle the command line arguments, with the aim of supporting:
|
||||||
|
* gdbus wait --session --activate ActivateName WaitName
|
||||||
|
* gdbus wait --session --activate ActivateAndWaitName
|
||||||
|
* gdbus wait --activate --session ActivateAndWaitName
|
||||||
|
* gdbus wait --session WaitName
|
||||||
|
*/
|
||||||
|
if (*argc == 2 && opt_wait_activate_set && opt_wait_activate_name != NULL)
|
||||||
|
{
|
||||||
|
activate_service = opt_wait_activate_name;
|
||||||
|
wait_service = (*argv)[1];
|
||||||
|
}
|
||||||
|
else if (*argc == 2 &&
|
||||||
|
opt_wait_activate_set && opt_wait_activate_name == NULL)
|
||||||
|
{
|
||||||
|
activate_service = (*argv)[1];
|
||||||
|
wait_service = (*argv)[1];
|
||||||
|
}
|
||||||
|
else if (*argc == 2 && !opt_wait_activate_set)
|
||||||
|
{
|
||||||
|
activate_service = NULL; /* disabled */
|
||||||
|
wait_service = (*argv)[1];
|
||||||
|
}
|
||||||
|
else if (*argc == 1 &&
|
||||||
|
opt_wait_activate_set && opt_wait_activate_name != NULL)
|
||||||
|
{
|
||||||
|
activate_service = opt_wait_activate_name;
|
||||||
|
wait_service = opt_wait_activate_name;
|
||||||
|
}
|
||||||
|
else if (*argc == 1 &&
|
||||||
|
opt_wait_activate_set && opt_wait_activate_name == NULL)
|
||||||
|
{
|
||||||
|
g_printerr (_("Error: A service to activate for must be specified.\n"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else if (*argc == 1 && !opt_wait_activate_set)
|
||||||
|
{
|
||||||
|
g_printerr (_("Error: A service to wait for must be specified.\n"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else /* if (*argc > 2) */
|
||||||
|
{
|
||||||
|
g_printerr (_("Error: Too many arguments.\n"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activate_service != NULL &&
|
||||||
|
(!g_dbus_is_name (activate_service) ||
|
||||||
|
g_dbus_is_unique_name (activate_service)))
|
||||||
|
{
|
||||||
|
g_printerr (_("Error: %s is not a valid well-known bus name.\n"),
|
||||||
|
activate_service);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_dbus_is_name (wait_service) || g_dbus_is_unique_name (wait_service))
|
||||||
|
{
|
||||||
|
g_printerr (_("Error: %s is not a valid well-known bus name.\n"),
|
||||||
|
wait_service);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All done with completion now */
|
||||||
|
if (request_completion)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Start the prerequisite service if needed. */
|
||||||
|
if (activate_service != NULL)
|
||||||
|
{
|
||||||
|
activate_watch_id = g_bus_watch_name_on_connection (c, activate_service,
|
||||||
|
G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
|
||||||
|
NULL, NULL,
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
activate_watch_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for the expected name to appear. */
|
||||||
|
watch_id = g_bus_watch_name_on_connection (c,
|
||||||
|
wait_service,
|
||||||
|
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||||
|
wait_name_appeared_cb,
|
||||||
|
NULL, &wait_state, NULL);
|
||||||
|
|
||||||
|
/* Safety timeout. */
|
||||||
|
if (opt_wait_timeout > 0)
|
||||||
|
timer_id = g_timeout_add (opt_wait_timeout, wait_timeout_cb, &wait_state);
|
||||||
|
|
||||||
|
while (wait_state == WAIT_STATE_RUNNING)
|
||||||
|
g_main_context_iteration (NULL, TRUE);
|
||||||
|
|
||||||
|
g_bus_unwatch_name (watch_id);
|
||||||
|
if (timer_id != 0)
|
||||||
|
g_source_remove (timer_id);
|
||||||
|
if (activate_watch_id != 0)
|
||||||
|
g_bus_unwatch_name (activate_watch_id);
|
||||||
|
|
||||||
|
ret = (wait_state == WAIT_STATE_SUCCESS);
|
||||||
|
|
||||||
|
out:
|
||||||
|
g_clear_object (&c);
|
||||||
|
g_option_context_free (o);
|
||||||
|
g_free (opt_wait_activate_name);
|
||||||
|
opt_wait_activate_name = NULL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
static gchar *
|
static gchar *
|
||||||
pick_word_at (const gchar *s,
|
pick_word_at (const gchar *s,
|
||||||
gint cursor,
|
gint cursor,
|
||||||
@ -2081,6 +2318,16 @@ main (gint argc, gchar *argv[])
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
else if (g_strcmp0 (command, "wait") == 0)
|
||||||
|
{
|
||||||
|
if (handle_wait (&argc,
|
||||||
|
&argv,
|
||||||
|
request_completion,
|
||||||
|
completion_cur,
|
||||||
|
completion_prev))
|
||||||
|
ret = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
else if (g_strcmp0 (command, "complete") == 0 && argc == 4 && !request_completion)
|
else if (g_strcmp0 (command, "complete") == 0 && argc == 4 && !request_completion)
|
||||||
{
|
{
|
||||||
const gchar *completion_line;
|
const gchar *completion_line;
|
||||||
@ -2150,7 +2397,7 @@ main (gint argc, gchar *argv[])
|
|||||||
{
|
{
|
||||||
if (request_completion)
|
if (request_completion)
|
||||||
{
|
{
|
||||||
g_print ("help \nemit \ncall \nintrospect \nmonitor \n");
|
g_print ("help \nemit \ncall \nintrospect \nmonitor \nwait \n");
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user