From: zefr0x Date: Sat, 17 Jan 2026 19:59:22 +0000 (+0300) Subject: busctl: handle `--limit-messages` option under the `wait` verb X-Git-Tag: v260-rc1~364 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=985a6fa44b58c307030e43950ff2affa3f32546a;p=thirdparty%2Fsystemd.git busctl: handle `--limit-messages` option under the `wait` verb Main focus was to not introduce breaking change or duplicated argument. The `--limit-messages=` option that is used under the `monitor` verb is reused here. However, both `wait` and `monitor` have contradicting default behaviors, so it's not the cleanest thing to do. There was some post-commit discussion about the API in #33961, but the final name adopted in #34928 wasn't that flexible either to fit nicely here in the `wait` verbe. Additionally, there wasn't consideration in #34555 for having uniform behavrious, so we ended with `wait` verb and `--limit-messages=` option, rather than `receive` verb with default of continuously receving signals withtout exit so `--limit-messages=` make more sence and be expectable. --- diff --git a/man/busctl.xml b/man/busctl.xml index 47a20e8c4c8..0034c15b73a 100644 --- a/man/busctl.xml +++ b/man/busctl.xml @@ -75,7 +75,7 @@ to or from this peer, identified by its well-known or unique name. Otherwise, show all messages on the bus. Use CtrlC - to terminate the dump. + to terminate the dump or limit it with the option. @@ -147,9 +147,10 @@ wait SERVICE OBJECT INTERFACE SIGNAL - Wait for a signal. Takes an object path, interface name, and signal name. To suppress - output of the returned data, use the option. The service name may be - omitted, in which case busctl will match signals from any sender. + Wait for a signal. Takes an object path, interface name, and signal name. Use the + option to wait for more than just one signal before exiting. To + suppress output of the returned data, use the option. The service name may + be omitted, in which case busctl will match signals from any sender. @@ -398,7 +399,14 @@ 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. + number of occurrences of specific D-Bus messages. While if not specified or is set to special value + infinity, the default is to keep monitoring without limitations. + + When used with the wait command, it will make busctl + exit when the specified number of DBus signals have been received and printed. Setting it to + special value infinity will sustain busctl to receive and + print signals continuously without limitations. When nothing is specified, the default is to exit + immediately after receiving and printing the first signal. diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c index 62ee0a14844..8c523dc02ba 100644 --- a/src/busctl/busctl.c +++ b/src/busctl/busctl.c @@ -72,6 +72,7 @@ static bool arg_watch_bind = false; static usec_t arg_timeout = 0; static const char *arg_destination = NULL; static uint64_t arg_limit_messages = UINT64_MAX; +static uint64_t arg_limit_signals = 1; STATIC_DESTRUCTOR_REGISTER(arg_matches, strv_freep); @@ -1931,8 +1932,24 @@ static int get_property(int argc, char **argv, void *userdata) { } static int on_bus_signal(sd_bus_message *msg, void *userdata, sd_bus_error *ret_error) { - return sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(ASSERT_PTR(msg))), - bus_message_dump(msg, /* flags= */ 0)); + int r; + + r = bus_message_dump(msg, /* flags= */ 0); + if (r < 0) + return sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(ASSERT_PTR(msg))), r); + + if (arg_limit_signals != UINT64_MAX) { + arg_limit_signals--; + + if (arg_limit_signals == 0) { + if (!arg_quiet && !sd_json_format_enabled(arg_json_format_flags)) + log_info("Received requested maximum number of signals, exiting."); + + return sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(ASSERT_PTR(msg))), 0); + } + } + + return 0; } static int wait_signal(int argc, char **argv, void *userdata) { @@ -2353,7 +2370,14 @@ static int parse_argv(int argc, char *argv[]) { case 'N': if (isempty(optarg)) { - arg_limit_messages = UINT64_MAX; /* Reset to default */ + /* Reset to default */ + arg_limit_messages = UINT64_MAX; + arg_limit_signals = 1; + break; + } + + if (streq(optarg, "infinity")) { + arg_limit_signals = arg_limit_messages = UINT64_MAX; break; } @@ -2363,6 +2387,7 @@ static int parse_argv(int argc, char *argv[]) { if (arg_limit_messages == 0) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--limit-messages= parameter cannot be 0"); + arg_limit_signals = arg_limit_messages; break; case '?': diff --git a/test/units/TEST-74-AUX-UTILS.busctl.sh b/test/units/TEST-74-AUX-UTILS.busctl.sh index 60e27d3f872..b8ae8da5682 100755 --- a/test/units/TEST-74-AUX-UTILS.busctl.sh +++ b/test/units/TEST-74-AUX-UTILS.busctl.sh @@ -57,10 +57,27 @@ busctl emit --auto-start=no --destination=systemd-logind.service \ /org/freedesktop/login1 org.freedesktop.login1.Manager \ PrepareForShutdown b false +signal_emit_command() { + echo "for i in \$(seq 1 ${1:?}); do busctl emit /test org.freedesktop.fake1 TestSignal s success; done" +} + systemd-run --quiet --service-type=notify --unit=test-busctl-wait --pty \ -p Environment=SYSTEMD_LOG_LEVEL=debug \ - -p ExecStartPost="busctl emit /test org.freedesktop.fake1 TestSignal s success" \ - busctl --timeout=30 wait /test org.freedesktop.fake1 TestSignal | grep -F 's "success"' >/dev/null + -p ExecStartPost="sh -c '$(signal_emit_command 1)'" \ + busctl --timeout=30 wait /test org.freedesktop.fake1 TestSignal | + grep -Fc 's "success"' | xargs test 1 -eq + +systemd-run --quiet --service-type=notify --unit=test-busctl-wait-limited --pty \ + -p Environment=SYSTEMD_LOG_LEVEL=debug \ + -p ExecStartPost="sh -c '$(signal_emit_command 5)'" \ + busctl --timeout=30 --limit-messages=3 wait /test org.freedesktop.fake1 TestSignal | + grep -Fc 's "success"' | xargs test 3 -eq + +systemd-run --quiet --service-type=notify --unit=test-busctl-wait-unlimited --pty \ + -p Environment=SYSTEMD_LOG_LEVEL=debug \ + -p ExecStartPost="sh -c '$(signal_emit_command 2)'" \ + busctl --timeout=3 --limit-messages=infinity wait /test org.freedesktop.fake1 TestSignal | + grep -Fc 's "success"' | xargs test 2 -eq busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ Version