]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
busctl: handle `--limit-messages` option under the `wait` verb
authorzefr0x <zer0-x.7ty50@aleeas.com>
Sat, 17 Jan 2026 19:59:22 +0000 (22:59 +0300)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 19 Jan 2026 13:41:33 +0000 (22:41 +0900)
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.

man/busctl.xml
src/busctl/busctl.c
test/units/TEST-74-AUX-UTILS.busctl.sh

index 47a20e8c4c8807e89a5c01d7fc5ade33d2edc6c9..0034c15b73a38a7cca45fdbc599d910192905ffd 100644 (file)
@@ -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
         <keycombo><keycap>Ctrl</keycap><keycap>C</keycap></keycombo>
-        to terminate the dump.</para>
+        to terminate the dump or limit it with the <option>--limit-messages=</option> option.</para>
 
         <xi:include href="version-info.xml" xpointer="v209"/></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 <command>busctl</command> will match signals from any sender.</para>
+        <listitem><para>Wait for a signal. Takes an object path, interface name, and signal name. Use the
+        <option>--limit-messages=</option> option to wait for more than just one signal before exiting. To
+        suppress output of the returned data, use the <option>--quiet</option> option. The service name may
+        be omitted, in which case <command>busctl</command> will match signals from any sender.</para>
 
         <xi:include href="version-info.xml" xpointer="v257"/></listitem>
       </varlistentry>
           <para>When used with the <command>monitor</command> command, if enabled will make
           <command>busctl</command> exit when the specified number of messages have been received and
           printed. This is useful in combination with <option>--match=</option>, to wait for the specified
-          number of occurrences of specific D-Bus messages.</para>
+          number of occurrences of specific D-Bus messages. While if not specified or is set to special value
+          <literal>infinity</literal>, the default is to keep monitoring without limitations.</para>
+
+          <para>When used with the <command>wait</command> command, it will make <command>busctl</command>
+          exit when the specified number of DBus signals have been received and printed. Setting it to
+          special value <literal>infinity</literal> will sustain <command>busctl</command> 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.</para>
 
         <xi:include href="version-info.xml" xpointer="v257"/>
         </listitem>
index 62ee0a14844cd400d5b0be006872013fc410ba66..8c523dc02bae2430a184f402370b5b839d931e31 100644 (file)
@@ -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 '?':
index 60e27d3f8726505c53943086e0bfcc2c75c06530..b8ae8da5682045ce232f5dbd49861d2b53521310 100755 (executable)
@@ -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