mirror of
https://github.com/systemd/systemd.git
synced 2025-01-09 01:18:19 +03:00
busctl: add wait verb to wait for signals
It's like busctl call, but it waits for a signal rather than a reply to a method call.
This commit is contained in:
parent
2b577d598b
commit
30465af656
@ -144,6 +144,16 @@
|
||||
<xi:include href="version-info.xml" xpointer="v242"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>wait</command> <arg choice="opt"><replaceable>SERVICE</replaceable></arg> <arg choice="plain"><replaceable>OBJECT</replaceable></arg> <arg choice="plain"><replaceable>INTERFACE</replaceable></arg> <arg choice="plain"><replaceable>SIGNAL</replaceable></arg></term>
|
||||
|
||||
<listitem><para>Wait for a signal. Takes an object path, interface name, and signal name. To suppress
|
||||
output of the returned data, use the <option>--quiet</option> option. The service name may be
|
||||
omitted, in which case busctl will match signals from any sender.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>get-property</command> <arg choice="plain"><replaceable>SERVICE</replaceable></arg> <arg choice="plain"><replaceable>OBJECT</replaceable></arg> <arg choice="plain"><replaceable>INTERFACE</replaceable></arg> <arg choice="plain" rep="repeat"><replaceable>PROPERTY</replaceable></arg></term>
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
"tree:Show object tree of service"
|
||||
"introspect:Introspect object"
|
||||
"call:Call a method"
|
||||
"wait:Wait for a signal"
|
||||
"get-property:Get property value"
|
||||
"set-property:Set property value"
|
||||
)
|
||||
@ -201,6 +202,31 @@ __dbus_matchspec() {
|
||||
esac
|
||||
}
|
||||
|
||||
(( $+functions[_busctl_wait] )) || _busctl_wait()
|
||||
{
|
||||
local expl
|
||||
case $CURRENT in
|
||||
2)
|
||||
_wanted busname expl 'busname' \
|
||||
compadd "$@" - $(_busctl_get_service_names)
|
||||
;;
|
||||
3)
|
||||
_wanted path expl 'path' \
|
||||
compadd "$@" - $(_busctl_get_objects $words[2])
|
||||
;;
|
||||
4)
|
||||
_wanted interface expl 'interface' \
|
||||
compadd "$@" - $(_busctl_get_interfaces $words[2,3])
|
||||
;;
|
||||
5)
|
||||
_wanted method expl 'method' \
|
||||
compadd "$@" - $(_busctl_get_members $words[2,4] "signal")
|
||||
;;
|
||||
*)
|
||||
_message "no more options"
|
||||
esac
|
||||
}
|
||||
|
||||
(( $+functions[_busctl_get-property] )) || _busctl_get-property()
|
||||
{
|
||||
local expl
|
||||
|
@ -2281,6 +2281,104 @@ static int get_property(int argc, char **argv, void *userdata) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_bus_signal_impl(sd_bus_message *msg) {
|
||||
int r;
|
||||
|
||||
assert(msg);
|
||||
|
||||
r = sd_bus_message_is_empty(msg);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
if (r > 0 || arg_quiet)
|
||||
return 0;
|
||||
|
||||
if (!FLAGS_SET(arg_json_format_flags, SD_JSON_FORMAT_OFF)) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||
|
||||
if (arg_json_format_flags & (SD_JSON_FORMAT_PRETTY|SD_JSON_FORMAT_PRETTY_AUTO))
|
||||
pager_open(arg_pager_flags);
|
||||
|
||||
r = json_transform_message(msg, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
sd_json_variant_dump(v, arg_json_format_flags, NULL, NULL);
|
||||
|
||||
} else if (arg_verbose) {
|
||||
pager_open(arg_pager_flags);
|
||||
|
||||
r = sd_bus_message_dump(msg, stdout, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to dump dbus message: %m\n");
|
||||
} else {
|
||||
|
||||
fputs(sd_bus_message_get_signature(msg, true), stdout);
|
||||
fputc(' ', stdout);
|
||||
|
||||
r = format_cmdline(msg, stdout, false);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
fputc('\n', stdout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_bus_signal(sd_bus_message *msg, void *userdata, sd_bus_error *ret_error) {
|
||||
sd_event *e = sd_bus_get_event(sd_bus_message_get_bus(ASSERT_PTR(msg)));
|
||||
return sd_event_exit(e, on_bus_signal_impl(msg));
|
||||
}
|
||||
|
||||
static int wait_signal(int argc, char **argv, void *userdata) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
|
||||
_cleanup_(sd_event_source_unrefp) sd_event_source *timer = NULL;
|
||||
int argn = 1, r;
|
||||
|
||||
const char *sender = argc == 5 ? argv[argn++] : NULL;
|
||||
const char *path = argv[argn++];
|
||||
const char *interface = argv[argn++];
|
||||
const char *member = argv[argn++];
|
||||
|
||||
if (sender && !service_name_is_valid(sender))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name: %s", sender);
|
||||
if (!object_path_is_valid(path))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid object path: %s", path);
|
||||
if (!interface_name_is_valid(interface))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid interface name: %s", interface);
|
||||
if (!member_name_is_valid(member))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid member name: %s", member);
|
||||
|
||||
r = acquire_bus(/* set_monitor= */ false, &bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_match_signal(bus, NULL, sender, path, interface, member, on_bus_signal, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to match signal %s on interface %s: %m", member, interface);
|
||||
|
||||
r = sd_event_new(&e);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate event loop: %m\n");
|
||||
|
||||
r = sd_bus_attach_event(bus, e, SD_EVENT_PRIORITY_NORMAL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to attach bus event: %m\n");
|
||||
|
||||
if (arg_timeout) {
|
||||
r = sd_event_add_time_relative(e, &timer, CLOCK_MONOTONIC, arg_timeout, 0, NULL, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to schedule timeout: %m\n");
|
||||
}
|
||||
|
||||
/* The match is installed and we're ready to observe the signal */
|
||||
sd_notify(/* unset_environment= */ false, "READY=1");
|
||||
|
||||
return sd_event_loop(e);
|
||||
}
|
||||
|
||||
static int set_property(int argc, char **argv, void *userdata) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
@ -2352,6 +2450,8 @@ static int help(void) {
|
||||
" Call a method\n"
|
||||
" emit OBJECT INTERFACE SIGNAL [SIGNATURE [ARGUMENT...]]\n"
|
||||
" Emit a signal\n"
|
||||
" wait OBJECT INTERFACE SIGNAL\n"
|
||||
" Wait for a signal\n"
|
||||
" get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
|
||||
" Get property value\n"
|
||||
" set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
|
||||
@ -2664,6 +2764,7 @@ static int busctl_main(int argc, char *argv[]) {
|
||||
{ "introspect", 3, 4, 0, introspect },
|
||||
{ "call", 5, VERB_ANY, 0, call },
|
||||
{ "emit", 4, VERB_ANY, 0, emit_signal },
|
||||
{ "wait", 4, 5, 0, wait_signal },
|
||||
{ "get-property", 5, VERB_ANY, 0, get_property },
|
||||
{ "set-property", 6, VERB_ANY, 0, set_property },
|
||||
{ "help", VERB_ANY, VERB_ANY, 0, verb_help },
|
||||
|
Loading…
Reference in New Issue
Block a user