diff --git a/man/busctl.xml b/man/busctl.xml index 6f940c3eb64..730a3344d6c 100644 --- a/man/busctl.xml +++ b/man/busctl.xml @@ -227,7 +227,24 @@ along with systemd; If not, see . call SERVICE OBJECT INTERFACE METHOD SIGNATURE PARAMETERS - Invoke a method and show the response. + Invoke a method and show the response. Takes a + service name, object path, interface name and method name. If + parameters shall be passed to the method call a signature + string is required, followed by the individual parameters, + individually formatted as textual arguments. + + + + get-property SERVICE OBJECT INTERFACE PROPERTIES + + Retrieve the current value one or more object + properties. Takes a service name and object path. Optionally + takes an interface name and property name. If the property + name is omited, shows all properties on the selected + interface. If the interface is also omitted shows the + properties of all interfaces. Multiple properties may be + specified at once in which case their values will be shown one + after the other. diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c index b13bc4b119b..28fcdda77bf 100644 --- a/src/libsystemd/sd-bus/bus-dump.c +++ b/src/libsystemd/sd-bus/bus-dump.c @@ -30,21 +30,34 @@ #include "bus-type.h" #include "bus-dump.h" -static char *indent(unsigned level) { +static char *indent(unsigned level, unsigned flags) { char *p; + unsigned n, i = 0; - p = new(char, 2 + level + 1); + n = 0; + + if (flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY && level > 0) + level -= 1; + + if (flags & BUS_MESSAGE_DUMP_WITH_HEADER) + n += 2; + + p = new(char, n + level*8 + 1); if (!p) return NULL; - p[0] = p[1] = ' '; - memset(p + 2, '\t', level); - p[2 + level] = 0; + if (flags & BUS_MESSAGE_DUMP_WITH_HEADER) { + p[i++] = ' '; + p[i++] = ' '; + } + + memset(p + i, ' ', level*8); + p[i + level*8] = 0; return p; } -int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) { +int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) { unsigned level = 1; int r; @@ -53,7 +66,7 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) { if (!f) f = stdout; - if (with_header) { + if (flags & BUS_MESSAGE_DUMP_WITH_HEADER) { fprintf(f, "%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u Priority=%lli", m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() : @@ -111,13 +124,14 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) { bus_creds_dump(&m->creds, f); } - r = sd_bus_message_rewind(m, true); + r = sd_bus_message_rewind(m, !(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY)); if (r < 0) { log_error("Failed to rewind: %s", strerror(-r)); return r; } - fprintf(f, " MESSAGE \"%s\" {\n", strempty(m->root_container.signature)); + if (!(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY)) + fprintf(f, "%sMESSAGE \"%s\" {\n", indent(0, flags), strempty(m->root_container.signature)); for (;;) { _cleanup_free_ char *prefix = NULL; @@ -154,7 +168,7 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) { level--; - prefix = indent(level); + prefix = indent(level, flags); if (!prefix) return log_oom(); @@ -162,7 +176,7 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) { continue; } - prefix = indent(level); + prefix = indent(level, flags); if (!prefix) return log_oom(); @@ -254,7 +268,9 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) { } } - fprintf(f, " };\n\n"); + if (!(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY)) + fprintf(f, "%s};\n\n", indent(0, flags)); + return 0; } diff --git a/src/libsystemd/sd-bus/bus-dump.h b/src/libsystemd/sd-bus/bus-dump.h index 6af0ab066cb..360c844cf96 100644 --- a/src/libsystemd/sd-bus/bus-dump.h +++ b/src/libsystemd/sd-bus/bus-dump.h @@ -26,7 +26,12 @@ #include "sd-bus.h" -int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header); +enum { + BUS_MESSAGE_DUMP_WITH_HEADER = 1, + BUS_MESSAGE_DUMP_SUBTREE_ONLY = 2, +}; + +int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags); int bus_creds_dump(sd_bus_creds *c, FILE *f); diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index 2bf890e88fa..6d03692c7f0 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -1023,7 +1023,7 @@ static int tree(sd_bus *bus, char **argv) { } static int message_dump(sd_bus_message *m, FILE *f) { - return bus_message_dump(m, f, true); + return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER); } static int message_pcap(sd_bus_message *m, FILE *f) { @@ -1445,7 +1445,108 @@ static int call(sd_bus *bus, char *argv[]) { return bus_log_parse_error(r); if (r == 0 && !arg_quiet) { pager_open_if_enabled(); - bus_message_dump(reply, stdout, false); + bus_message_dump(reply, stdout, 0); + } + + return 0; +} + +static int get_property(sd_bus *bus, char *argv[]) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + unsigned n; + int r; + + assert(bus); + + n = strv_length(argv); + if (n < 3) { + log_error("Expects at least three arguments."); + return -EINVAL; + } + + if (n < 5) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + bool not_first = false; + + r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", strempty(argv[3])); + if (r < 0) { + log_error("%s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_enter_container(reply, 'a', "{sv}"); + if (r < 0) + return bus_log_parse_error(r); + + for (;;) { + const char *name; + + r = sd_bus_message_enter_container(reply, 'e', "sv"); + if (r < 0) + return bus_log_parse_error(r); + + if (r == 0) + break; + + r = sd_bus_message_read(reply, "s", &name); + if (r < 0) + return bus_log_parse_error(r); + + if (not_first) + printf("\n"); + + printf("Property %s:\n", name); + + r = sd_bus_message_enter_container(reply, 'v', NULL); + if (r < 0) + return bus_log_parse_error(r); + + pager_open_if_enabled(); + bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + not_first = true; + } + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + } else { + char **i; + + STRV_FOREACH(i, argv + 4) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + + r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i); + if (r < 0) { + log_error("%s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_enter_container(reply, 'v', NULL); + if (r < 0) + return bus_log_parse_error(r); + + if (i > argv + 4) + printf("\n"); + + if (argv[5]) + printf("Property %s:\n", *i); + + pager_open_if_enabled(); + bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + } } return 0; @@ -1476,8 +1577,10 @@ static int help(void) { " monitor [SERVICE...] Show bus traffic\n" " capture [SERVICE...] Capture bus traffic as pcap\n" " status SERVICE Show service name status\n" - " call SERVICE PATH INTERFACE METHOD [SIGNATURE] [ARGUMENTS...]\n" + " call SERVICE PATH INTERFACE METHOD [SIGNATURE [ARGUMENTS...]]\n" " Call a method\n" + " get-property SERVICE PATH [INTERFACE [PROPERTY...]]\n" + " Get property value\n" " help Show this help\n" , program_invocation_short_name); @@ -1649,6 +1752,9 @@ static int busctl_main(sd_bus *bus, int argc, char *argv[]) { if (streq(argv[optind], "call")) return call(bus, argv + optind); + if (streq(argv[optind], "get-property")) + return get_property(bus, argv + optind); + if (streq(argv[optind], "help")) return help(); diff --git a/src/libsystemd/sd-bus/test-bus-gvariant.c b/src/libsystemd/sd-bus/test-bus-gvariant.c index 92268588250..56df5d0b48e 100644 --- a/src/libsystemd/sd-bus/test-bus-gvariant.c +++ b/src/libsystemd/sd-bus/test-bus-gvariant.c @@ -175,14 +175,14 @@ static void test_marshal(void) { } #endif - assert_se(bus_message_dump(m, NULL, true) >= 0); + assert_se(bus_message_dump(m, NULL, BUS_MESSAGE_DUMP_WITH_HEADER) >= 0); assert_se(bus_message_get_blob(m, &blob, &sz) >= 0); assert_se(bus_message_from_malloc(bus, blob, sz, NULL, 0, NULL, NULL, &n) >= 0); blob = NULL; - assert_se(bus_message_dump(n, NULL, true) >= 0); + assert_se(bus_message_dump(n, NULL, BUS_MESSAGE_DUMP_WITH_HEADER) >= 0); m = sd_bus_message_unref(m); @@ -191,7 +191,7 @@ static void test_marshal(void) { assert_se(sd_bus_message_append(m, "as", 0) >= 0); assert_se(bus_message_seal(m, 4712, 0) >= 0); - assert_se(bus_message_dump(m, NULL, true) >= 0); + assert_se(bus_message_dump(m, NULL, BUS_MESSAGE_DUMP_WITH_HEADER) >= 0); } int main(int argc, char *argv[]) { diff --git a/src/libsystemd/sd-bus/test-bus-kernel.c b/src/libsystemd/sd-bus/test-bus-kernel.c index b138d390d9e..9cc0f01c5b5 100644 --- a/src/libsystemd/sd-bus/test-bus-kernel.c +++ b/src/libsystemd/sd-bus/test-bus-kernel.c @@ -117,7 +117,7 @@ int main(int argc, char *argv[]) { assert_se(r > 0); assert_se(m); - bus_message_dump(m, stdout, true); + bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER); assert_se(sd_bus_message_rewind(m, true) >= 0); r = sd_bus_message_read(m, "s", &the_string); @@ -154,7 +154,7 @@ int main(int argc, char *argv[]) { assert_se(r > 0); assert_se(m); - bus_message_dump(m, stdout, true); + bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER); assert_se(sd_bus_message_rewind(m, true) >= 0); if (sd_bus_message_is_method_call(m, "an.inter.face", "AMethod")) { diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c index 95321125247..8cefc7a154e 100644 --- a/src/libsystemd/sd-bus/test-bus-marshal.c +++ b/src/libsystemd/sd-bus/test-bus-marshal.c @@ -148,10 +148,10 @@ int main(int argc, char *argv[]) { r = bus_message_seal(m, 4711, 0); assert_se(r >= 0); - bus_message_dump(m, stdout, true); + bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER); ms = open_memstream(&first, &first_size); - bus_message_dump(m, ms, false); + bus_message_dump(m, ms, 0); fflush(ms); assert_se(!ferror(ms)); @@ -201,11 +201,11 @@ int main(int argc, char *argv[]) { r = bus_message_from_malloc(bus, buffer, sz, NULL, 0, NULL, NULL, &m); assert_se(r >= 0); - bus_message_dump(m, stdout, true); + bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER); fclose(ms); ms = open_memstream(&second, &second_size); - bus_message_dump(m, ms, false); + bus_message_dump(m, ms, 0); fflush(ms); assert_se(!ferror(ms)); assert_se(first_size == second_size); @@ -285,7 +285,7 @@ int main(int argc, char *argv[]) { fclose(ms); ms = open_memstream(&third, &third_size); - bus_message_dump(copy, ms, false); + bus_message_dump(copy, ms, 0); fflush(ms); assert_se(!ferror(ms)); diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c index e7a445f3cbb..1324e912fcd 100644 --- a/src/libsystemd/sd-bus/test-bus-objects.c +++ b/src/libsystemd/sd-bus/test-bus-objects.c @@ -385,7 +385,7 @@ static int client(struct context *c) { r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", ""); assert_se(r >= 0); - bus_message_dump(reply, stdout, true); + bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER); sd_bus_message_unref(reply); reply = NULL; @@ -403,7 +403,7 @@ static int client(struct context *c) { r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, ""); assert_se(r >= 0); - bus_message_dump(reply, stdout, true); + bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER); sd_bus_message_unref(reply); reply = NULL; @@ -415,7 +415,7 @@ static int client(struct context *c) { assert_se(r > 0); assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged")); - bus_message_dump(reply, stdout, true); + bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER); sd_bus_message_unref(reply); reply = NULL; @@ -427,7 +427,7 @@ static int client(struct context *c) { assert_se(r > 0); assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged")); - bus_message_dump(reply, stdout, true); + bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER); sd_bus_message_unref(reply); reply = NULL; @@ -439,7 +439,7 @@ static int client(struct context *c) { assert_se(r > 0); assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded")); - bus_message_dump(reply, stdout, true); + bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER); sd_bus_message_unref(reply); reply = NULL; @@ -451,7 +451,7 @@ static int client(struct context *c) { assert_se(r > 0); assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved")); - bus_message_dump(reply, stdout, true); + bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER); sd_bus_message_unref(reply); reply = NULL; diff --git a/src/libsystemd/sd-bus/test-bus-zero-copy.c b/src/libsystemd/sd-bus/test-bus-zero-copy.c index e938a48b639..2cc671b16d1 100644 --- a/src/libsystemd/sd-bus/test-bus-zero-copy.c +++ b/src/libsystemd/sd-bus/test-bus-zero-copy.c @@ -138,7 +138,7 @@ int main(int argc, char *argv[]) { r = bus_message_seal(m, 55, 99*USEC_PER_SEC); assert_se(r >= 0); - bus_message_dump(m, stdout, true); + bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER); r = sd_bus_send(b, m, NULL); assert_se(r >= 0); @@ -148,7 +148,7 @@ int main(int argc, char *argv[]) { r = sd_bus_process(a, &m); assert_se(r > 0); - bus_message_dump(m, stdout, true); + bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER); sd_bus_message_rewind(m, true); r = sd_bus_message_enter_container(m, 'r', "aysay");