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