mirror of
https://github.com/systemd/systemd.git
synced 2024-11-23 18:23:32 +08:00
busctl: introduce busctl "get-property" command for reading and dumping object properties
This commit is contained in:
parent
2e75e2a8f5
commit
d55192add7
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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[]) {
|
||||
|
@ -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")) {
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user