chiark / gitweb /
busctl: introduce busctl "get-property" command for reading and dumping object properties
authorLennart Poettering <lennart@poettering.net>
Fri, 14 Nov 2014 16:20:04 +0000 (17:20 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 14 Nov 2014 16:52:40 +0000 (17:52 +0100)
man/busctl.xml
src/libsystemd/sd-bus/bus-dump.c
src/libsystemd/sd-bus/bus-dump.h
src/libsystemd/sd-bus/busctl.c
src/libsystemd/sd-bus/test-bus-gvariant.c
src/libsystemd/sd-bus/test-bus-kernel.c
src/libsystemd/sd-bus/test-bus-marshal.c
src/libsystemd/sd-bus/test-bus-objects.c
src/libsystemd/sd-bus/test-bus-zero-copy.c

index 6f940c3..730a334 100644 (file)
@@ -227,7 +227,24 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
       <varlistentry>
         <term><command>call</command> <arg choice="plain"><replaceable>SERVICE</replaceable></arg> <arg choice="plain"><replaceable>OBJECT</replaceable></arg> <arg choice="plain"><replaceable>INTERFACE</replaceable></arg> <arg choice="plain"><replaceable>METHOD</replaceable></arg> <arg choice="opt"><replaceable>SIGNATURE</replaceable> <arg choice="opt" rep="repeat"><replaceable>PARAMETERS</replaceable></arg></arg></term>
 
-        <listitem><para>Invoke a method and show the response.</para></listitem>
+        <listitem><para>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.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><command>get-property</command> <arg choice="plain"><replaceable>SERVICE</replaceable></arg> <arg choice="plain"><replaceable>OBJECT</replaceable></arg> <arg choice="opt"><replaceable>INTERFACE</replaceable> <arg choice="opt" rep="repeat"><replaceable>PROPERTIES</replaceable></arg></arg></term>
+
+        <listitem><para>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.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index b13bc4b..28fcdda 100644 (file)
 #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;
 }
 
index 6af0ab0..360c844 100644 (file)
 
 #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);
 
index 2bf890e..6d03692 100644 (file)
@@ -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();
 
index 9226858..56df5d0 100644 (file)
@@ -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[]) {
index b138d39..9cc0f01 100644 (file)
@@ -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")) {
index 9532112..8cefc7a 100644 (file)
@@ -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));
 
index e7a445f..1324e91 100644 (file)
@@ -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;
index e938a48..2cc671b 100644 (file)
@@ -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");