busctl: introduce busctl "get-property" command for reading and dumping object properties

This commit is contained in:
Lennart Poettering 2014-11-14 17:20:04 +01:00
parent 2e75e2a8f5
commit d55192add7
9 changed files with 179 additions and 35 deletions

View 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>

View File

@ -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;
}

View File

@ -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);

View 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();

View 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[]) {

View 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")) {

View 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));

View 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;

View 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");