sd-bus: introduce sd_bus_message_dump_json()

We have already expose sd_bus_message_dump(). Let's also expose how
we convert dbus message into json format in busctl.
This commit is contained in:
Yu Watanabe
2025-04-27 23:06:34 +09:00
parent 71c4b42efc
commit 0c111392fd
8 changed files with 403 additions and 399 deletions

View File

@@ -326,7 +326,7 @@ manpages = [
['sd_bus_message_append_strv', '3', [], ''],
['sd_bus_message_at_end', '3', [], ''],
['sd_bus_message_copy', '3', [], ''],
['sd_bus_message_dump', '3', [], ''],
['sd_bus_message_dump', '3', ['sd_bus_message_dump_json'], ''],
['sd_bus_message_get_cookie', '3', ['sd_bus_message_get_reply_cookie'], ''],
['sd_bus_message_get_monotonic_usec',
'3',

View File

@@ -18,6 +18,7 @@
<refnamediv>
<refname>sd_bus_message_dump</refname>
<refname>sd_bus_message_dump_json</refname>
<refpurpose>Produce a string representation of a message for debugging purposes</refpurpose>
</refnamediv>
@@ -32,12 +33,14 @@
<paramdef>FILE *<parameter>f</parameter></paramdef>
<paramdef>uint64_t <parameter>flags</parameter></paramdef>
</funcprototype>
</funcsynopsis>
<para>
<constant>SD_BUS_MESSAGE_DUMP_WITH_HEADER</constant>,
<constant>SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY</constant>
</para>
<funcprototype>
<funcdef>int sd_bus_message_dump_json</funcdef>
<paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
<paramdef>uint64_t <parameter>flags</parameter></paramdef>
<paramdef>sd_json_variant **<parameter>ret</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
@@ -49,16 +52,38 @@
intended to be used for debugging purposes, and the output is neither stable nor designed to be machine
readable.</para>
<para>The <parameter>flags</parameter> parameter may be used to modify the output. With
<constant>SD_BUS_MESSAGE_DUMP_WITH_HEADER</constant>, a header that specifies the message type and flags
and some additional metadata is printed. When <constant>SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY</constant> is
not passed, the contents of the whole message are printed. When it <emphasis>is</emphasis> passed,
only the current container in printed.</para>
<para>The <function>sd_bus_message_dump_json()</function> function converts the DBus message
<parameter>m</parameter> to a JSON variant and stores it in <parameter>ret</parameter>. The caller should
call <function>sd_json_variant_unref()</function> for the acquired JSON variant after use. Unlike
<function>sd_bus_message_dump()</function>, the function itself does not print anything. To print the
DBus message in the JSON format, please pass the returned JSON variant to
<function>sd_json_variant_dump()</function>.</para>
<para>Note that this function moves the read pointer of the message. It may be necessary to reset the
<para>The <parameter>flags</parameter> parameter may be used to modify the output, and is a combination
of zero or more of the following flags:</para>
<variablelist>
<varlistentry>
<term><constant>SD_BUS_MESSAGE_DUMP_WITH_HEADER</constant></term>
<listitem><para>The header of the message that specifies the message type, flags, and several more
additional metadata will be printed or included in the resulting JSON object.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY</constant></term>
<listitem><para>Only the current container will be printed or converted. When the flag is
<emphasis>not</emphasis> specified, the contents of the whole message will be printed or converted.
</para></listitem>
</varlistentry>
</variablelist>
<para>Note that these functions move the read pointer of the message. It may be necessary to reset the
position afterwards, for example with
<citerefentry><refentrytitle>sd_bus_message_rewind</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</para>
</refsect1>
<refsect1>
@@ -102,6 +127,7 @@
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>sd-json</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>

View File

@@ -74,8 +74,6 @@ STATIC_DESTRUCTOR_REGISTER(arg_matches, strv_freep);
#define NAME_IS_ACQUIRED INT_TO_PTR(1)
#define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
static int json_transform_message(sd_bus_message *m, sd_json_variant **ret);
static int acquire_bus(bool set_monitor, sd_bus **ret) {
_cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
_cleanup_close_ int pin_fd = -EBADF;
@@ -1201,44 +1199,19 @@ static int message_pcap(sd_bus_message *m, FILE *f) {
}
static int message_json(sd_bus_message *m, FILE *f) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *w = NULL;
char e[2];
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
int r;
usec_t ts;
r = json_transform_message(m, &v);
assert(m);
r = sd_bus_message_dump_json(m, SD_BUS_MESSAGE_DUMP_WITH_HEADER, &v);
if (r < 0)
return r;
return log_error_errno(r, "Failed to build JSON object from DBus message: %m");
e[0] = m->header->endian;
e[1] = 0;
ts = m->realtime;
if (ts == 0)
ts = now(CLOCK_REALTIME);
r = sd_json_buildo(&w,
SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(bus_message_type_to_string(m->header->type))),
SD_JSON_BUILD_PAIR("endian", SD_JSON_BUILD_STRING(e)),
SD_JSON_BUILD_PAIR("flags", SD_JSON_BUILD_INTEGER(m->header->flags)),
SD_JSON_BUILD_PAIR("version", SD_JSON_BUILD_INTEGER(m->header->version)),
SD_JSON_BUILD_PAIR("cookie", SD_JSON_BUILD_INTEGER(BUS_MESSAGE_COOKIE(m))),
SD_JSON_BUILD_PAIR_CONDITION(m->reply_cookie != 0, "reply_cookie", SD_JSON_BUILD_INTEGER(m->reply_cookie)),
SD_JSON_BUILD_PAIR("timestamp-realtime", SD_JSON_BUILD_UNSIGNED(ts)),
SD_JSON_BUILD_PAIR_CONDITION(!!m->sender, "sender", SD_JSON_BUILD_STRING(m->sender)),
SD_JSON_BUILD_PAIR_CONDITION(!!m->destination, "destination", SD_JSON_BUILD_STRING(m->destination)),
SD_JSON_BUILD_PAIR_CONDITION(!!m->path, "path", SD_JSON_BUILD_STRING(m->path)),
SD_JSON_BUILD_PAIR_CONDITION(!!m->interface, "interface", SD_JSON_BUILD_STRING(m->interface)),
SD_JSON_BUILD_PAIR_CONDITION(!!m->member, "member", SD_JSON_BUILD_STRING(m->member)),
SD_JSON_BUILD_PAIR_CONDITION(m->monotonic != 0, "monotonic", SD_JSON_BUILD_INTEGER(m->monotonic)),
SD_JSON_BUILD_PAIR_CONDITION(m->realtime != 0, "realtime", SD_JSON_BUILD_INTEGER(m->realtime)),
SD_JSON_BUILD_PAIR_CONDITION(m->seqnum != 0, "seqnum", SD_JSON_BUILD_INTEGER(m->seqnum)),
SD_JSON_BUILD_PAIR_CONDITION(!!m->error.name, "error_name", SD_JSON_BUILD_STRING(m->error.name)),
SD_JSON_BUILD_PAIR("payload", SD_JSON_BUILD_VARIANT(v)));
r = sd_json_variant_dump(v, arg_json_format_flags, f, NULL);
if (r < 0)
return log_error_errno(r, "Failed to build JSON object: %m");
return log_error_errno(r, "Failed to show JSON object: %m");
sd_json_variant_dump(w, arg_json_format_flags, f, NULL);
return 0;
}
@@ -1721,355 +1694,6 @@ static int message_append_cmdline(sd_bus_message *m, const char *signature, FDSe
return 0;
}
static int json_transform_one(sd_bus_message *m, sd_json_variant **ret);
static int json_transform_and_append(sd_bus_message *m, sd_json_variant **array) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *element = NULL;
int r;
assert(m);
assert(array);
r = json_transform_one(m, &element);
if (r < 0)
return r;
r = sd_json_variant_append_array(array, element);
if (r < 0)
return log_error_errno(r, "Failed to append json element to array: %m");
return 0;
}
static int json_transform_array_or_struct(sd_bus_message *m, sd_json_variant **ret) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *array = NULL;
int r;
assert(m);
assert(ret);
r = sd_json_variant_new_array(&array, NULL, 0);
if (r < 0)
return log_error_errno(r, "Failed to allocate json empty array: %m");
for (;;) {
r = sd_bus_message_at_end(m, false);
if (r < 0)
return bus_log_parse_error(r);
if (r > 0)
break;
r = json_transform_and_append(m, &array);
if (r < 0)
return r;
}
*ret = TAKE_PTR(array);
return 0;
}
static int json_transform_variant(sd_bus_message *m, const char *contents, sd_json_variant **ret) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *value = NULL;
int r;
assert(m);
assert(contents);
assert(ret);
r = json_transform_one(m, &value);
if (r < 0)
return r;
r = sd_json_buildo(ret,
SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(contents)),
SD_JSON_BUILD_PAIR("data", SD_JSON_BUILD_VARIANT(value)));
if (r < 0)
return log_error_errno(r, "Failed to build json object: %m");
return r;
}
static int json_transform_dict_array(sd_bus_message *m, sd_json_variant **ret) {
sd_json_variant **elements = NULL;
size_t n_elements = 0;
int r;
assert(m);
assert(ret);
CLEANUP_ARRAY(elements, n_elements, sd_json_variant_unref_many);
for (;;) {
const char *contents;
char type;
r = sd_bus_message_at_end(m, false);
if (r < 0)
return bus_log_parse_error(r);
if (r > 0)
break;
r = sd_bus_message_peek_type(m, &type, &contents);
if (r < 0)
return bus_log_parse_error(r);
assert(type == 'e');
if (!GREEDY_REALLOC(elements, n_elements + 2))
return log_oom();
r = sd_bus_message_enter_container(m, type, contents);
if (r < 0)
return bus_log_parse_error(r);
r = json_transform_one(m, elements + n_elements);
if (r < 0)
return r;
n_elements++;
r = json_transform_one(m, elements + n_elements);
if (r < 0)
return r;
n_elements++;
r = sd_bus_message_exit_container(m);
if (r < 0)
return bus_log_parse_error(r);
}
r = sd_json_variant_new_object(ret, elements, n_elements);
if (r < 0)
return log_error_errno(r, "Failed to create new json object: %m");
return 0;
}
static int json_transform_one(sd_bus_message *m, sd_json_variant **ret) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
const char *contents;
char type;
int r;
assert(m);
assert(ret);
r = sd_bus_message_peek_type(m, &type, &contents);
if (r < 0)
return bus_log_parse_error(r);
switch (type) {
case SD_BUS_TYPE_BYTE: {
uint8_t b;
r = sd_bus_message_read_basic(m, type, &b);
if (r < 0)
return bus_log_parse_error(r);
r = sd_json_variant_new_unsigned(&v, b);
if (r < 0)
return log_error_errno(r, "Failed to transform byte: %m");
break;
}
case SD_BUS_TYPE_BOOLEAN: {
int b;
r = sd_bus_message_read_basic(m, type, &b);
if (r < 0)
return bus_log_parse_error(r);
r = sd_json_variant_new_boolean(&v, b);
if (r < 0)
return log_error_errno(r, "Failed to transform boolean: %m");
break;
}
case SD_BUS_TYPE_INT16: {
int16_t b;
r = sd_bus_message_read_basic(m, type, &b);
if (r < 0)
return bus_log_parse_error(r);
r = sd_json_variant_new_integer(&v, b);
if (r < 0)
return log_error_errno(r, "Failed to transform int16: %m");
break;
}
case SD_BUS_TYPE_UINT16: {
uint16_t b;
r = sd_bus_message_read_basic(m, type, &b);
if (r < 0)
return bus_log_parse_error(r);
r = sd_json_variant_new_unsigned(&v, b);
if (r < 0)
return log_error_errno(r, "Failed to transform uint16: %m");
break;
}
case SD_BUS_TYPE_INT32: {
int32_t b;
r = sd_bus_message_read_basic(m, type, &b);
if (r < 0)
return bus_log_parse_error(r);
r = sd_json_variant_new_integer(&v, b);
if (r < 0)
return log_error_errno(r, "Failed to transform int32: %m");
break;
}
case SD_BUS_TYPE_UINT32: {
uint32_t b;
r = sd_bus_message_read_basic(m, type, &b);
if (r < 0)
return bus_log_parse_error(r);
r = sd_json_variant_new_unsigned(&v, b);
if (r < 0)
return log_error_errno(r, "Failed to transform uint32: %m");
break;
}
case SD_BUS_TYPE_INT64: {
int64_t b;
r = sd_bus_message_read_basic(m, type, &b);
if (r < 0)
return bus_log_parse_error(r);
r = sd_json_variant_new_integer(&v, b);
if (r < 0)
return log_error_errno(r, "Failed to transform int64: %m");
break;
}
case SD_BUS_TYPE_UINT64: {
uint64_t b;
r = sd_bus_message_read_basic(m, type, &b);
if (r < 0)
return bus_log_parse_error(r);
r = sd_json_variant_new_unsigned(&v, b);
if (r < 0)
return log_error_errno(r, "Failed to transform uint64: %m");
break;
}
case SD_BUS_TYPE_DOUBLE: {
double d;
r = sd_bus_message_read_basic(m, type, &d);
if (r < 0)
return bus_log_parse_error(r);
r = sd_json_variant_new_real(&v, d);
if (r < 0)
return log_error_errno(r, "Failed to transform double: %m");
break;
}
case SD_BUS_TYPE_STRING:
case SD_BUS_TYPE_OBJECT_PATH:
case SD_BUS_TYPE_SIGNATURE: {
const char *s;
r = sd_bus_message_read_basic(m, type, &s);
if (r < 0)
return bus_log_parse_error(r);
r = sd_json_variant_new_string(&v, s);
if (r < 0)
return log_error_errno(r, "Failed to transform double: %m");
break;
}
case SD_BUS_TYPE_UNIX_FD: {
int fd;
r = sd_bus_message_read_basic(m, type, &fd);
if (r < 0)
return bus_log_parse_error(r);
r = json_variant_new_fd_info(&v, fd);
if (r < 0)
return log_error_errno(r, "Failed to transform fd: %m");
break;
}
case SD_BUS_TYPE_ARRAY:
case SD_BUS_TYPE_VARIANT:
case SD_BUS_TYPE_STRUCT:
r = sd_bus_message_enter_container(m, type, contents);
if (r < 0)
return bus_log_parse_error(r);
if (type == SD_BUS_TYPE_VARIANT)
r = json_transform_variant(m, contents, &v);
else if (type == SD_BUS_TYPE_ARRAY && contents[0] == '{')
r = json_transform_dict_array(m, &v);
else
r = json_transform_array_or_struct(m, &v);
if (r < 0)
return r;
r = sd_bus_message_exit_container(m);
if (r < 0)
return bus_log_parse_error(r);
break;
default:
assert_not_reached();
}
*ret = TAKE_PTR(v);
return 0;
}
static int json_transform_message(sd_bus_message *m, sd_json_variant **ret) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
const char *type;
int r;
assert(m);
assert(ret);
assert_se(type = sd_bus_message_get_signature(m, false));
r = json_transform_array_or_struct(m, &v);
if (r < 0)
return r;
r = sd_json_buildo(ret,
SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(type)),
SD_JSON_BUILD_PAIR("data", SD_JSON_BUILD_VARIANT(v)));
if (r < 0)
return log_error_errno(r, "Failed to build json object: %m");
return 0;
}
static int call(int argc, char **argv, void *userdata) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -2146,7 +1770,7 @@ static int call(int argc, char **argv, void *userdata) {
if (arg_json_format_flags & (SD_JSON_FORMAT_PRETTY|SD_JSON_FORMAT_PRETTY_AUTO))
pager_open(arg_pager_flags);
r = json_transform_message(reply, &v);
r = sd_bus_message_dump_json(reply, /* flags = */ 0, &v);
if (r < 0)
return r;
@@ -2256,7 +1880,7 @@ static int get_property(int argc, char **argv, void *userdata) {
if (arg_json_format_flags & (SD_JSON_FORMAT_PRETTY|SD_JSON_FORMAT_PRETTY_AUTO))
pager_open(arg_pager_flags);
r = json_transform_variant(reply, contents, &v);
r = sd_bus_message_dump_json(reply, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY, &v);
if (r < 0)
return r;
@@ -2304,7 +1928,7 @@ static int on_bus_signal_impl(sd_bus_message *msg) {
if (arg_json_format_flags & (SD_JSON_FORMAT_PRETTY|SD_JSON_FORMAT_PRETTY_AUTO))
pager_open(arg_pager_flags);
r = json_transform_message(msg, &v);
r = sd_bus_message_dump_json(msg, /* flags = */ 0, &v);
if (r < 0)
return r;

View File

@@ -1062,6 +1062,7 @@ global:
LIBSYSTEMD_258 {
global:
sd_bus_message_dump_json;
sd_device_enumerator_add_all_parents;
sd_json_variant_type_from_string;
sd_json_variant_type_to_string;

View File

@@ -65,6 +65,7 @@ sd_bus_sources = files(
'sd-bus/bus-convenience.c',
'sd-bus/bus-creds.c',
'sd-bus/bus-dump.c',
'sd-bus/bus-dump-json.c',
'sd-bus/bus-error.c',
'sd-bus/bus-internal.c',
'sd-bus/bus-introspect.c',

View File

@@ -0,0 +1,346 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-bus.h"
#include "alloc-util.h"
#include "bus-internal.h"
#include "bus-message.h"
#include "json-util.h"
#include "macro.h"
#include "memory-util.h"
#include "time-util.h"
static int json_transform_one(sd_bus_message *m, sd_json_variant **ret);
static int json_transform_array_or_struct(sd_bus_message *m, sd_json_variant **ret) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *array = NULL;
int r;
assert(m);
assert(ret);
r = sd_json_variant_new_array(&array, NULL, 0);
if (r < 0)
return r;
for (;;) {
r = sd_bus_message_at_end(m, false);
if (r < 0)
return r;
if (r > 0)
break;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
r = json_transform_one(m, &v);
if (r < 0)
return r;
r = sd_json_variant_append_array(&array, v);
if (r < 0)
return r;
}
*ret = TAKE_PTR(array);
return 0;
}
static int json_transform_variant(sd_bus_message *m, const char *contents, sd_json_variant **ret) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *value = NULL;
int r;
assert(m);
assert(contents);
assert(ret);
r = json_transform_one(m, &value);
if (r < 0)
return r;
return sd_json_buildo(
ret,
SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(contents)),
SD_JSON_BUILD_PAIR("data", SD_JSON_BUILD_VARIANT(value)));
}
static int json_transform_dict_array(sd_bus_message *m, sd_json_variant **ret) {
sd_json_variant **elements = NULL;
size_t n_elements = 0;
int r;
assert(m);
assert(ret);
CLEANUP_ARRAY(elements, n_elements, sd_json_variant_unref_many);
for (;;) {
const char *contents;
char type;
r = sd_bus_message_at_end(m, false);
if (r < 0)
return r;
if (r > 0)
break;
r = sd_bus_message_peek_type(m, &type, &contents);
if (r < 0)
return r;
assert(type == 'e');
if (!GREEDY_REALLOC(elements, n_elements + 2))
return -ENOMEM;
r = sd_bus_message_enter_container(m, type, contents);
if (r < 0)
return r;
r = json_transform_one(m, elements + n_elements);
if (r < 0)
return r;
n_elements++;
r = json_transform_one(m, elements + n_elements);
if (r < 0)
return r;
n_elements++;
r = sd_bus_message_exit_container(m);
if (r < 0)
return r;
}
return sd_json_variant_new_object(ret, elements, n_elements);
}
static int json_transform_one(sd_bus_message *m, sd_json_variant **ret) {
const char *contents;
char type;
int r;
assert(m);
assert(ret);
r = sd_bus_message_peek_type(m, &type, &contents);
if (r < 0)
return r;
switch (type) {
case SD_BUS_TYPE_BYTE: {
uint8_t b;
r = sd_bus_message_read_basic(m, type, &b);
if (r < 0)
return r;
return sd_json_variant_new_unsigned(ret, b);
}
case SD_BUS_TYPE_BOOLEAN: {
int b;
r = sd_bus_message_read_basic(m, type, &b);
if (r < 0)
return r;
return sd_json_variant_new_boolean(ret, b);
}
case SD_BUS_TYPE_INT16: {
int16_t b;
r = sd_bus_message_read_basic(m, type, &b);
if (r < 0)
return r;
return sd_json_variant_new_integer(ret, b);
}
case SD_BUS_TYPE_UINT16: {
uint16_t b;
r = sd_bus_message_read_basic(m, type, &b);
if (r < 0)
return r;
return sd_json_variant_new_unsigned(ret, b);
}
case SD_BUS_TYPE_INT32: {
int32_t b;
r = sd_bus_message_read_basic(m, type, &b);
if (r < 0)
return r;
return sd_json_variant_new_integer(ret, b);
}
case SD_BUS_TYPE_UINT32: {
uint32_t b;
r = sd_bus_message_read_basic(m, type, &b);
if (r < 0)
return r;
return sd_json_variant_new_unsigned(ret, b);
}
case SD_BUS_TYPE_INT64: {
int64_t b;
r = sd_bus_message_read_basic(m, type, &b);
if (r < 0)
return r;
return sd_json_variant_new_integer(ret, b);
}
case SD_BUS_TYPE_UINT64: {
uint64_t b;
r = sd_bus_message_read_basic(m, type, &b);
if (r < 0)
return r;
return sd_json_variant_new_unsigned(ret, b);
}
case SD_BUS_TYPE_DOUBLE: {
double d;
r = sd_bus_message_read_basic(m, type, &d);
if (r < 0)
return r;
return sd_json_variant_new_real(ret, d);
}
case SD_BUS_TYPE_STRING:
case SD_BUS_TYPE_OBJECT_PATH:
case SD_BUS_TYPE_SIGNATURE: {
const char *s;
r = sd_bus_message_read_basic(m, type, &s);
if (r < 0)
return r;
return sd_json_variant_new_string(ret, s);
}
case SD_BUS_TYPE_UNIX_FD: {
int fd;
r = sd_bus_message_read_basic(m, type, &fd);
if (r < 0)
return r;
return json_variant_new_fd_info(ret, fd);
}
case SD_BUS_TYPE_ARRAY:
case SD_BUS_TYPE_VARIANT:
case SD_BUS_TYPE_STRUCT: {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
r = sd_bus_message_enter_container(m, type, contents);
if (r < 0)
return r;
if (type == SD_BUS_TYPE_VARIANT)
r = json_transform_variant(m, contents, &v);
else if (type == SD_BUS_TYPE_ARRAY && contents[0] == '{')
r = json_transform_dict_array(m, &v);
else
r = json_transform_array_or_struct(m, &v);
if (r < 0)
return r;
r = sd_bus_message_exit_container(m);
if (r < 0)
return r;
*ret = TAKE_PTR(v);
return 0;
}
default:
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"sd-bus: an invalid message type (signature=%s, type=%c, contents=%s).",
sd_bus_message_get_signature(m, /* complete = */ false), type, strna(contents));
}
}
static int json_transform_message(sd_bus_message *m, const char *type, sd_json_variant **ret) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
int r;
assert(m);
assert(type);
assert(ret);
r = json_transform_array_or_struct(m, &v);
if (r < 0)
return r;
return sd_json_buildo(
ret,
SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(type)),
SD_JSON_BUILD_PAIR("data", SD_JSON_BUILD_VARIANT(v)));
}
_public_ int sd_bus_message_dump_json(sd_bus_message *m, uint64_t flags, sd_json_variant **ret) {
int r;
assert_return(m, -EINVAL);
assert_return((flags & ~_SD_BUS_MESSAGE_DUMP_KNOWN_FLAGS) == 0, -EINVAL);
assert_return(ret, -EINVAL);
r = sd_bus_message_rewind(m, !FLAGS_SET(flags, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY));
if (r < 0)
return r;
const char *type = sd_bus_message_get_signature(m, !FLAGS_SET(flags, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY));
if (!type)
return -EINVAL;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
if (FLAGS_SET(flags, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY))
r = json_transform_variant(m, type, &v);
else
r = json_transform_message(m, type, &v);
if (r < 0)
return r;
if (!FLAGS_SET(flags, SD_BUS_MESSAGE_DUMP_WITH_HEADER)) {
*ret = TAKE_PTR(v);
return 0;
}
usec_t ts = m->realtime;
if (ts == 0)
ts = now(CLOCK_REALTIME);
return sd_json_buildo(
ret,
SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(bus_message_type_to_string(m->header->type))),
SD_JSON_BUILD_PAIR("endian", SD_JSON_BUILD_STRING(CHAR_TO_STR(m->header->endian))),
SD_JSON_BUILD_PAIR("flags", SD_JSON_BUILD_INTEGER(m->header->flags)),
SD_JSON_BUILD_PAIR("version", SD_JSON_BUILD_INTEGER(m->header->version)),
SD_JSON_BUILD_PAIR("cookie", SD_JSON_BUILD_INTEGER(BUS_MESSAGE_COOKIE(m))),
SD_JSON_BUILD_PAIR_CONDITION(m->reply_cookie != 0, "reply_cookie", SD_JSON_BUILD_INTEGER(m->reply_cookie)),
SD_JSON_BUILD_PAIR("timestamp-realtime", SD_JSON_BUILD_UNSIGNED(ts)),
SD_JSON_BUILD_PAIR_CONDITION(!!m->sender, "sender", SD_JSON_BUILD_STRING(m->sender)),
SD_JSON_BUILD_PAIR_CONDITION(!!m->destination, "destination", SD_JSON_BUILD_STRING(m->destination)),
SD_JSON_BUILD_PAIR_CONDITION(!!m->path, "path", SD_JSON_BUILD_STRING(m->path)),
SD_JSON_BUILD_PAIR_CONDITION(!!m->interface, "interface", SD_JSON_BUILD_STRING(m->interface)),
SD_JSON_BUILD_PAIR_CONDITION(!!m->member, "member", SD_JSON_BUILD_STRING(m->member)),
SD_JSON_BUILD_PAIR_CONDITION(m->monotonic != 0, "monotonic", SD_JSON_BUILD_INTEGER(m->monotonic)),
SD_JSON_BUILD_PAIR_CONDITION(m->realtime != 0, "realtime", SD_JSON_BUILD_INTEGER(m->realtime)),
SD_JSON_BUILD_PAIR_CONDITION(m->seqnum != 0, "seqnum", SD_JSON_BUILD_INTEGER(m->seqnum)),
SD_JSON_BUILD_PAIR_CONDITION(!!m->error.name, "error_name", SD_JSON_BUILD_STRING(m->error.name)),
SD_JSON_BUILD_PAIR("payload", SD_JSON_BUILD_VARIANT(v)));
}

View File

@@ -33,7 +33,11 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (getenv_bool("SYSTEMD_FUZZ_OUTPUT") <= 0)
assert_se(g = memstream_init(&ms));
sd_bus_message_dump(m, g ?: stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
(void) sd_bus_message_dump(m, g, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
if (sd_bus_message_dump_json(m, SD_BUS_MESSAGE_DUMP_WITH_HEADER, &v) >= 0)
(void) sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY | SD_JSON_FORMAT_COLOR_AUTO, g, NULL);
r = sd_bus_message_rewind(m, true);
assert_se(r >= 0);

View File

@@ -28,6 +28,7 @@
#include "sd-bus-vtable.h"
#include "sd-event.h"
#include "sd-id128.h"
#include "sd-json.h"
_SD_BEGIN_DECLARATIONS;
@@ -257,6 +258,7 @@ int sd_bus_message_rewind(sd_bus_message *m, int complete);
int sd_bus_message_sensitive(sd_bus_message *m);
int sd_bus_message_dump(sd_bus_message *m, FILE *f, uint64_t flags);
int sd_bus_message_dump_json(sd_bus_message *m, uint64_t flags, sd_json_variant **ret);
/* Bus management */