From 989e843e7543b21b91de4368da44692d674722a5 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Wed, 7 Aug 2024 20:41:20 +0100 Subject: [PATCH 1/2] busctl: add support for --timeout to monitor verb Useful in scripts when you want to exit successfully after a certain time --- man/busctl.xml | 18 +++++++++--------- shell-completion/zsh/_busctl | 2 +- src/busctl/busctl.c | 7 ++++++- test/units/TEST-74-AUX-UTILS.busctl.sh | 2 ++ 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/man/busctl.xml b/man/busctl.xml index 27327ee192..0938582c8b 100644 --- a/man/busctl.xml +++ b/man/busctl.xml @@ -392,15 +392,15 @@ - When used with the call command, - specifies the maximum time to wait for method call - completion. If no time unit is specified, assumes - seconds. The usual other units are understood, too (ms, us, - s, min, h, d, w, month, y). Note that this timeout does not - apply if is used, as the - tool does not wait for any reply message then. When not - specified or when set to 0, the default of - 25s is assumed. + When used with the call command, specifies the maximum time to wait for + method call completion. When used with the monitor command, since version v257, + specifies the maximum time to wait for messages before automatically exiting. If no time unit is + specified, assumes seconds. The usual other units are understood, too (ms, us, s, min, h, d, w, + month, y). Note that this timeout does not apply if is used, + when combined with the call command, as the tool does not wait for any reply + message then. When not specified or when set to 0, the default of 25s is + assumed for the call command, and it is disabled for the + monitor command. diff --git a/shell-completion/zsh/_busctl b/shell-completion/zsh/_busctl index d8d7adfb4c..c8c4f96ed1 100644 --- a/shell-completion/zsh/_busctl +++ b/shell-completion/zsh/_busctl @@ -282,6 +282,6 @@ _arguments \ '--expect-reply=[Expect a method call reply]:boolean:(1 0)' \ '--auto-start=[Auto-start destination service]:boolean:(1 0)' \ '--allow-interactive-authorization=[Allow interactive authorization for operation]:boolean:(1 0)' \ - '--timeout=[Maximum time to wait for method call completion]:timeout (seconds)' \ + '--timeout=[Maximum time to wait for method call completion and monitoring]:timeout (seconds)' \ '--augment-creds=[Extend credential data with data read from /proc/$PID]:boolean:(1 0)' \ '*::busctl command:_busctl_commands' diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c index 4a5fac7606..31104f36c5 100644 --- a/src/busctl/busctl.c +++ b/src/busctl/busctl.c @@ -1373,7 +1373,12 @@ static int monitor(int argc, char **argv, int (*dump)(sd_bus_message *m, FILE *f if (r > 0) continue; - r = sd_bus_wait(bus, UINT64_MAX); + r = sd_bus_wait(bus, arg_timeout > 0 ? arg_timeout : UINT64_MAX); + if (r == 0 && arg_timeout > 0) { + if (!arg_quiet && arg_json_format_flags == SD_JSON_FORMAT_OFF) + log_info("Timed out waiting for messages, exiting."); + return 0; + } if (r < 0) return log_error_errno(r, "Failed to wait for bus: %m"); } diff --git a/test/units/TEST-74-AUX-UTILS.busctl.sh b/test/units/TEST-74-AUX-UTILS.busctl.sh index aaf96d08c1..6e997b46c6 100755 --- a/test/units/TEST-74-AUX-UTILS.busctl.sh +++ b/test/units/TEST-74-AUX-UTILS.busctl.sh @@ -108,3 +108,5 @@ busctl get-property -j \ # Invalid argument (! busctl set-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ KExecWatchdogUSec t "foo") + +busctl --quiet --timeout 1 --match "interface=org.freedesktop.systemd1.Manager" monitor >/dev/null From 702d74b62a65e46f083172d4454ad9ebf10b5e0d Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Wed, 7 Aug 2024 21:59:26 +0100 Subject: [PATCH 2/2] busctl: add --num-matches= for monitor verb Useful in scripts when one wants to wait for a specific signal before continuing --- man/busctl.xml | 13 +++++++++++++ shell-completion/bash/busctl | 2 +- shell-completion/zsh/_busctl | 1 + src/busctl/busctl.c | 20 ++++++++++++++++++++ test/units/TEST-74-AUX-UTILS.busctl.sh | 2 +- 5 files changed, 36 insertions(+), 2 deletions(-) diff --git a/man/busctl.xml b/man/busctl.xml index 0938582c8b..c313d29955 100644 --- a/man/busctl.xml +++ b/man/busctl.xml @@ -406,6 +406,19 @@ + + + + + When used with the monitor command, if enabled will make + busctl exit when the specified number of messages have been received and + printed. This is useful in combination with , to wait for the specified + number of occurrences of specific D-Bus messages. + + + + + diff --git a/shell-completion/bash/busctl b/shell-completion/bash/busctl index bb80c17683..ea88cca8c6 100644 --- a/shell-completion/bash/busctl +++ b/shell-completion/bash/busctl @@ -89,7 +89,7 @@ _busctl() { --allow-interactive-authorization=no --augment-creds=no --watch-bind=yes -j -l --full --xml-interface' [ARG]='--address -H --host -M --machine --match --timeout --size --json - --destination' + --destination --num-matches' ) if __contains_word "--user" ${COMP_WORDS[*]}; then diff --git a/shell-completion/zsh/_busctl b/shell-completion/zsh/_busctl index c8c4f96ed1..0018cf6622 100644 --- a/shell-completion/zsh/_busctl +++ b/shell-completion/zsh/_busctl @@ -284,4 +284,5 @@ _arguments \ '--allow-interactive-authorization=[Allow interactive authorization for operation]:boolean:(1 0)' \ '--timeout=[Maximum time to wait for method call completion and monitoring]:timeout (seconds)' \ '--augment-creds=[Extend credential data with data read from /proc/$PID]:boolean:(1 0)' \ + '--num-matches=[Exit after receiving a number of matches while monitoring]:integer' \ '*::busctl command:_busctl_commands' diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c index 31104f36c5..3735337a80 100644 --- a/src/busctl/busctl.c +++ b/src/busctl/busctl.c @@ -63,6 +63,7 @@ static bool arg_augment_creds = true; static bool arg_watch_bind = false; static usec_t arg_timeout = 0; static const char *arg_destination = NULL; +static uint64_t arg_num_matches = UINT64_MAX; STATIC_DESTRUCTOR_REGISTER(arg_matches, strv_freep); @@ -1361,6 +1362,12 @@ static int monitor(int argc, char **argv, int (*dump)(sd_bus_message *m, FILE *f dump(m, stdout); fflush(stdout); + if (arg_num_matches != UINT64_MAX && --arg_num_matches == 0) { + if (!arg_quiet && arg_json_format_flags == SD_JSON_FORMAT_OFF) + log_info("Received requested number of matching messages, exiting."); + return 0; + } + if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected") > 0) { if (!arg_quiet && arg_json_format_flags == SD_JSON_FORMAT_OFF) log_info("Connection terminated, exiting."); @@ -2361,6 +2368,8 @@ static int help(void) { " --watch-bind=BOOL Wait for bus AF_UNIX socket to be bound in the file\n" " system\n" " --destination=SERVICE Destination service of a signal\n" + " --num-matches=NUMBER Exit after receiving a number of matches while\n" + " monitoring\n" "\nSee the %s for details.\n", program_invocation_short_name, ansi_highlight(), @@ -2400,6 +2409,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_WATCH_BIND, ARG_JSON, ARG_DESTINATION, + ARG_NUM_MATCHES, }; static const struct option options[] = { @@ -2432,6 +2442,7 @@ static int parse_argv(int argc, char *argv[]) { { "watch-bind", required_argument, NULL, ARG_WATCH_BIND }, { "json", required_argument, NULL, ARG_JSON }, { "destination", required_argument, NULL, ARG_DESTINATION }, + { "num-matches", required_argument, NULL, ARG_NUM_MATCHES }, {}, }; @@ -2600,6 +2611,15 @@ static int parse_argv(int argc, char *argv[]) { arg_destination = optarg; break; + case ARG_NUM_MATCHES: + r = safe_atou64(optarg, &arg_num_matches); + if (r < 0) + return log_error_errno(r, "Failed to parse --num-matches= parameter '%s': %m", optarg); + if (arg_num_matches == 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--num-matches= parameter cannot be 0"); + + break; + case '?': return -EINVAL; diff --git a/test/units/TEST-74-AUX-UTILS.busctl.sh b/test/units/TEST-74-AUX-UTILS.busctl.sh index 6e997b46c6..3ef94e5cb9 100755 --- a/test/units/TEST-74-AUX-UTILS.busctl.sh +++ b/test/units/TEST-74-AUX-UTILS.busctl.sh @@ -109,4 +109,4 @@ busctl get-property -j \ (! busctl set-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ KExecWatchdogUSec t "foo") -busctl --quiet --timeout 1 --match "interface=org.freedesktop.systemd1.Manager" monitor >/dev/null +busctl --quiet --timeout 1 --num-matches 1 --match "interface=org.freedesktop.systemd1.Manager" monitor >/dev/null