1
0
mirror of https://github.com/systemd/systemd.git synced 2024-10-26 17:27:41 +03:00

Merge pull request #34555 from rpigott/busctl-wait

busctl: add wait verb to wait for signals
This commit is contained in:
Yu Watanabe 2024-10-13 18:50:48 +09:00 committed by GitHub
commit 4a7fd9d1d5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 141 additions and 0 deletions

View File

@ -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>

View File

@ -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

View File

@ -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 },

View File

@ -53,6 +53,10 @@ busctl emit --auto-start=no --destination=systemd-logind.service \
/org/freedesktop/login1 org.freedesktop.login1.Manager \
PrepareForShutdown b false
systemd-run --quiet --service-type=notify --unit=test-busctl-wait --pty \
-p ExecStartPost="busctl emit /test org.freedesktop.fake1 TestSignal s success" \
busctl --timeout=3 wait /test org.freedesktop.fake1 TestSignal | grep -qF 's "success"'
busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \
Version
busctl get-property --verbose \