sd-bus: drop D-Bus version 2 format support

It seems the format is used only by kdbus.
This commit is contained in:
Yu Watanabe 2022-05-27 05:37:47 +09:00
parent c0f664ca89
commit 0dd4876815
11 changed files with 437 additions and 2446 deletions

1
TODO
View file

@ -1356,7 +1356,6 @@ Features:
- longer term: priority inheritance
- dbus spec updates:
- NameLost/NameAcquired obsolete
- GVariant
- path escaping
- update systemd.special(7) to mention that dbus.socket is only about the compatibility socket now

View file

@ -1,111 +0,0 @@
---
title: GVariant D-Bus Message Serialization
category: Interfaces
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# GVariant D-Bus Message Serialization
We stay as close to the original dbus1 framing as possible, but make
certain changes to adapt for GVariant. dbus1 has the following
framing:
1. A fixed header of "yyyyuu"
2. Additional header fields of "a(yv)"
3. Padding with NUL bytes to pad up to next 8byte boundary
4. The body
Note that the body is not padded at the end, the complete message
hence might have a non-aligned size. Reading multiple messages at once
will hence result in possibly unaligned messages in memory.
The header consists of the following:
y Endianness, 'l' or 'B'
y Message Type
y Flags
y Protocol version, '1'
u Length of the body, i.e. the length of part 4 above
u 32bit Serial number
= 12 bytes
This header is then followed by the fields array, whose first value is
a 32bit array size.
When using GVariant we keep the basic structure in place, only
slightly alter the header, and define protocol version '2'. The new
header:
y Endianness, 'l' or 'B'
y Message Type
y Flags
y Protocol version, '2'
u Reserved, must be 0
t 64bit Cookie
= 16 bytes
This is then followed by the GVariant fields array ("a{tv}"), and
finally the actual body as variant (v). Putting this altogether a
packet on dbus2 hence qualifies as a fully compliant GVariant
structure of (yyyyuta{tv}v).
For details on gvariant, see:
https://people.gnome.org/~desrt/gvariant-serialisation.pdf
Regarding the framing of dbus2, also see:
https://wiki.gnome.org/Projects/GLib/GDBus/Version2
The first four bytes of the header are defined the same way for dbus1
and dbus2. The first bytes contain the endianness field and the
protocol version, so that the remainder of the message can be safely
made sense of just by looking at the first 32bit.
Note that the length of the body is no longer included in the header
on dbus2! In fact, the message size must be known in advance, from the
underlying transport in order to parse dbus2 messages, while it is
directly included in dbus1 message headers. This change of semantics
is an effect of GVariant's basic design.
The serial number has been renamed cookie and has been extended from
32bit to 64bit. It is recommended to avoid the higher 32bit of the
cookie field though, to simplify compatibility with dbus1 peers. Note
that not only the cookie/serial field in the fixed header, but also
the reply_cookie/reply_serial additional header field has been
increased from 32bit to 64bit, too!
The header field identifiers have been extended from 8bit to
64bit. This has been done to simplify things, and has no effect
on the serialization size, as due to alignment for each 8bit
header field identifier 56 bits of padding had to be added.
Note that the header size changed, due to these changes. However,
consider that on dbus1 the beginning of the fields array contains the
32bit array size (since that is how arrays are encoded on dbus1),
thus, if one considers that size part of the header, instead of the
array, the size of the header on dbus1 and dbus2 stays identical, at
16 bytes.
0 4 8 12 16
Common: | E | T | F | V | ...
dbus1: | (as above) | Body Length | Serial | Fields Length | Fields array ...
gvariant: | (as above) | Reserved | Cookie | Fields array ...
And that's already it.
Note: To simplify parsing, valid dbus2 messages must include the entire
fixed header and additional header fields in a single non-memfd
message part. Also, the signature string of the body variant all the
way to the end of the message must be in a single non-memfd part
too. The parts for this extended header and footer can be the same
one, and can also continue any amount of additional body bytes.
Note: The GVariant "MAYBE" type is not supported, so that messages can
be fully converted forth and back between dbus1 and gvariant
representations.

View file

@ -3928,7 +3928,6 @@ install_data('LICENSE.GPL2',
'docs/TRANSIENT-SETTINGS.md',
'docs/TRANSLATORS.md',
'docs/UIDS-GIDS.md',
'docs/GVARIANT-SERIALIZATION.md',
install_dir : docdir)
install_subdir('LICENSES',

View file

@ -95,8 +95,6 @@ libsystemd_sources = files(
'sd-bus/bus-dump.h',
'sd-bus/bus-error.c',
'sd-bus/bus-error.h',
'sd-bus/bus-gvariant.c',
'sd-bus/bus-gvariant.h',
'sd-bus/bus-internal.c',
'sd-bus/bus-internal.h',
'sd-bus/bus-introspect.c',
@ -262,12 +260,6 @@ tests += [
[files('sd-bus/test-bus-vtable.c',
'sd-bus/test-vtable-data.h')],
[files('sd-bus/test-bus-gvariant.c'),
[],
[libglib,
libgobject,
libgio]],
[files('sd-bus/test-bus-creds.c')],
[files('sd-bus/test-bus-match.c')],

View file

@ -1,299 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <string.h>
#include "sd-bus.h"
#include "bus-gvariant.h"
#include "bus-signature.h"
#include "bus-type.h"
int bus_gvariant_get_size(const char *signature) {
const char *p;
int sum = 0, r;
/* For fixed size structs. Fails for variable size structs. */
p = signature;
while (*p != 0) {
size_t n;
r = signature_element_length(p, &n);
if (r < 0)
return r;
else {
char t[n+1];
memcpy(t, p, n);
t[n] = 0;
r = bus_gvariant_get_alignment(t);
if (r < 0)
return r;
sum = ALIGN_TO(sum, r);
}
switch (*p) {
case SD_BUS_TYPE_BOOLEAN:
case SD_BUS_TYPE_BYTE:
sum += 1;
break;
case SD_BUS_TYPE_INT16:
case SD_BUS_TYPE_UINT16:
sum += 2;
break;
case SD_BUS_TYPE_INT32:
case SD_BUS_TYPE_UINT32:
case SD_BUS_TYPE_UNIX_FD:
sum += 4;
break;
case SD_BUS_TYPE_INT64:
case SD_BUS_TYPE_UINT64:
case SD_BUS_TYPE_DOUBLE:
sum += 8;
break;
case SD_BUS_TYPE_STRUCT_BEGIN:
case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
if (n == 2) {
/* unary type () has fixed size of 1 */
r = 1;
} else {
char t[n-1];
memcpy(t, p + 1, n - 2);
t[n - 2] = 0;
r = bus_gvariant_get_size(t);
if (r < 0)
return r;
}
sum += r;
break;
}
case SD_BUS_TYPE_STRING:
case SD_BUS_TYPE_OBJECT_PATH:
case SD_BUS_TYPE_SIGNATURE:
case SD_BUS_TYPE_ARRAY:
case SD_BUS_TYPE_VARIANT:
return -EINVAL;
default:
assert_not_reached();
}
p += n;
}
r = bus_gvariant_get_alignment(signature);
if (r < 0)
return r;
return ALIGN_TO(sum, r);
}
int bus_gvariant_get_alignment(const char *signature) {
size_t alignment = 1;
const char *p;
int r;
p = signature;
while (*p != 0 && alignment < 8) {
size_t n;
int a;
r = signature_element_length(p, &n);
if (r < 0)
return r;
switch (*p) {
case SD_BUS_TYPE_BYTE:
case SD_BUS_TYPE_BOOLEAN:
case SD_BUS_TYPE_STRING:
case SD_BUS_TYPE_OBJECT_PATH:
case SD_BUS_TYPE_SIGNATURE:
a = 1;
break;
case SD_BUS_TYPE_INT16:
case SD_BUS_TYPE_UINT16:
a = 2;
break;
case SD_BUS_TYPE_INT32:
case SD_BUS_TYPE_UINT32:
case SD_BUS_TYPE_UNIX_FD:
a = 4;
break;
case SD_BUS_TYPE_INT64:
case SD_BUS_TYPE_UINT64:
case SD_BUS_TYPE_DOUBLE:
case SD_BUS_TYPE_VARIANT:
a = 8;
break;
case SD_BUS_TYPE_ARRAY: {
char t[n];
memcpy(t, p + 1, n - 1);
t[n - 1] = 0;
a = bus_gvariant_get_alignment(t);
break;
}
case SD_BUS_TYPE_STRUCT_BEGIN:
case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
char t[n-1];
memcpy(t, p + 1, n - 2);
t[n - 2] = 0;
a = bus_gvariant_get_alignment(t);
break;
}
default:
assert_not_reached();
}
if (a < 0)
return a;
assert(a > 0 && a <= 8);
if ((size_t) a > alignment)
alignment = (size_t) a;
p += n;
}
return alignment;
}
int bus_gvariant_is_fixed_size(const char *signature) {
const char *p;
int r;
assert(signature);
p = signature;
while (*p != 0) {
size_t n;
r = signature_element_length(p, &n);
if (r < 0)
return r;
switch (*p) {
case SD_BUS_TYPE_STRING:
case SD_BUS_TYPE_OBJECT_PATH:
case SD_BUS_TYPE_SIGNATURE:
case SD_BUS_TYPE_ARRAY:
case SD_BUS_TYPE_VARIANT:
return 0;
case SD_BUS_TYPE_BYTE:
case SD_BUS_TYPE_BOOLEAN:
case SD_BUS_TYPE_INT16:
case SD_BUS_TYPE_UINT16:
case SD_BUS_TYPE_INT32:
case SD_BUS_TYPE_UINT32:
case SD_BUS_TYPE_UNIX_FD:
case SD_BUS_TYPE_INT64:
case SD_BUS_TYPE_UINT64:
case SD_BUS_TYPE_DOUBLE:
break;
case SD_BUS_TYPE_STRUCT_BEGIN:
case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
char t[n-1];
memcpy(t, p + 1, n - 2);
t[n - 2] = 0;
r = bus_gvariant_is_fixed_size(t);
if (r <= 0)
return r;
break;
}
default:
assert_not_reached();
}
p += n;
}
return true;
}
size_t bus_gvariant_determine_word_size(size_t sz, size_t extra) {
if (sz + extra <= 0xFF)
return 1;
else if (sz + extra*2 <= 0xFFFF)
return 2;
else if (sz + extra*4 <= 0xFFFFFFFF)
return 4;
else
return 8;
}
size_t bus_gvariant_read_word_le(void *p, size_t sz) {
union {
uint16_t u16;
uint32_t u32;
uint64_t u64;
} x;
assert(p);
if (sz == 1)
return *(uint8_t*) p;
memcpy(&x, p, sz);
if (sz == 2)
return le16toh(x.u16);
else if (sz == 4)
return le32toh(x.u32);
else if (sz == 8)
return le64toh(x.u64);
assert_not_reached();
}
void bus_gvariant_write_word_le(void *p, size_t sz, size_t value) {
union {
uint16_t u16;
uint32_t u32;
uint64_t u64;
} x;
assert(p);
assert(sz == 8 || (value < (1ULL << (sz*8))));
if (sz == 1) {
*(uint8_t*) p = value;
return;
} else if (sz == 2)
x.u16 = htole16((uint16_t) value);
else if (sz == 4)
x.u32 = htole32((uint32_t) value);
else if (sz == 8)
x.u64 = htole64((uint64_t) value);
else
assert_not_reached();
memcpy(p, &x, sz);
}

View file

@ -1,12 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "macro.h"
int bus_gvariant_get_size(const char *signature) _pure_;
int bus_gvariant_get_alignment(const char *signature) _pure_;
int bus_gvariant_is_fixed_size(const char *signature) _pure_;
size_t bus_gvariant_determine_word_size(size_t sz, size_t extra);
void bus_gvariant_write_word_le(void *p, size_t sz, size_t value);
size_t bus_gvariant_read_word_le(void *p, size_t sz);

File diff suppressed because it is too large Load diff

View file

@ -14,21 +14,16 @@
struct bus_container {
char enclosing;
bool need_offsets:1;
/* Indexes into the signature string */
/* Indexes into the signature string */
unsigned index, saved_index;
char *signature;
size_t before, begin, end;
/* dbus1: pointer to the array size value, if this is a value */
/* pointer to the array size value, if this is a value */
uint32_t *array_size;
/* gvariant: list of offsets to end of children if this is struct/dict entry/array */
size_t *offsets, n_offsets, offset_index;
size_t item_size;
char *peeked_signature;
};
@ -86,13 +81,8 @@ struct sd_bus_message {
bool poisoned:1;
bool sensitive:1;
/* The first and last bytes of the message */
/* The first bytes of the message */
struct bus_header *header;
void *footer;
/* How many bytes are accessible in the above pointers */
size_t header_accessible;
size_t footer_accessible;
size_t fields_size;
size_t body_size;
@ -148,10 +138,7 @@ static inline uint64_t BUS_MESSAGE_BSWAP64(sd_bus_message *m, uint64_t u) {
}
static inline uint64_t BUS_MESSAGE_COOKIE(sd_bus_message *m) {
if (m->header->version == 2)
return BUS_MESSAGE_BSWAP64(m, m->header->dbus2.cookie);
return BUS_MESSAGE_BSWAP32(m, m->header->dbus1.serial);
return BUS_MESSAGE_BSWAP32(m, m->header->serial);
}
static inline size_t BUS_MESSAGE_SIZE(sd_bus_message *m) {
@ -171,10 +158,6 @@ static inline void* BUS_MESSAGE_FIELDS(sd_bus_message *m) {
return (uint8_t*) m->header + sizeof(struct bus_header);
}
static inline bool BUS_MESSAGE_IS_GVARIANT(sd_bus_message *m) {
return m->header->version == 2;
}
int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz);
int bus_message_read_strv_extend(sd_bus_message *m, char ***l);

View file

@ -8,32 +8,15 @@
/* Packet header */
struct _packed_ bus_header {
/* The first four fields are identical for dbus1, and dbus2 */
uint8_t endian;
uint8_t type;
uint8_t flags;
uint8_t version;
union _packed_ {
/* dbus1: Used for SOCK_STREAM connections */
struct _packed_ {
uint32_t body_size;
/* Note that what the bus spec calls "serial" we'll call
"cookie" instead, because we don't want to imply that the
cookie was in any way monotonically increasing. */
uint32_t serial;
uint32_t fields_size;
} dbus1;
/* dbus2: Used for kdbus connections */
struct _packed_ {
uint32_t _reserved;
uint64_t cookie;
} dbus2;
/* Note that both header versions have the same size! */
};
uint32_t body_size;
/* Note that what the bus spec calls "serial" we'll call "cookie" instead, because we don't
* want to imply that the cookie was in any way monotonically increasing. */
uint32_t serial;
uint32_t fields_size;
};
/* Endianness */

View file

@ -1966,9 +1966,7 @@ int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m) {
* hence let's fill something in for synthetic messages. Since
* synthetic messages might have a fake sender and we don't
* want to interfere with the real sender's serial numbers we
* pick a fixed, artificial one. We use UINT32_MAX rather
* than UINT64_MAX since dbus1 only had 32bit identifiers,
* even though kdbus can do 64bit. */
* pick a fixed, artificial one. */
return sd_bus_message_seal(m, UINT32_MAX, 0);
}

View file

@ -1,206 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#if HAVE_GLIB
#include <glib.h>
#endif
#include "sd-bus.h"
#include "alloc-util.h"
#include "bus-dump.h"
#include "bus-gvariant.h"
#include "bus-internal.h"
#include "bus-message.h"
#include "macro.h"
#include "tests.h"
#include "util.h"
TEST(bus_gvariant_is_fixed_size) {
assert_se(bus_gvariant_is_fixed_size("") > 0);
assert_se(bus_gvariant_is_fixed_size("()") == -EINVAL);
assert_se(bus_gvariant_is_fixed_size("y") > 0);
assert_se(bus_gvariant_is_fixed_size("u") > 0);
assert_se(bus_gvariant_is_fixed_size("b") > 0);
assert_se(bus_gvariant_is_fixed_size("n") > 0);
assert_se(bus_gvariant_is_fixed_size("q") > 0);
assert_se(bus_gvariant_is_fixed_size("i") > 0);
assert_se(bus_gvariant_is_fixed_size("t") > 0);
assert_se(bus_gvariant_is_fixed_size("d") > 0);
assert_se(bus_gvariant_is_fixed_size("s") == 0);
assert_se(bus_gvariant_is_fixed_size("o") == 0);
assert_se(bus_gvariant_is_fixed_size("g") == 0);
assert_se(bus_gvariant_is_fixed_size("h") > 0);
assert_se(bus_gvariant_is_fixed_size("ay") == 0);
assert_se(bus_gvariant_is_fixed_size("v") == 0);
assert_se(bus_gvariant_is_fixed_size("(u)") > 0);
assert_se(bus_gvariant_is_fixed_size("(uuuuy)") > 0);
assert_se(bus_gvariant_is_fixed_size("(uusuuy)") == 0);
assert_se(bus_gvariant_is_fixed_size("a{ss}") == 0);
assert_se(bus_gvariant_is_fixed_size("((u)yyy(b(iiii)))") > 0);
assert_se(bus_gvariant_is_fixed_size("((u)yyy(b(iiivi)))") == 0);
}
TEST(bus_gvariant_get_size) {
assert_se(bus_gvariant_get_size("") == 0);
assert_se(bus_gvariant_get_size("()") == -EINVAL);
assert_se(bus_gvariant_get_size("y") == 1);
assert_se(bus_gvariant_get_size("u") == 4);
assert_se(bus_gvariant_get_size("b") == 1);
assert_se(bus_gvariant_get_size("n") == 2);
assert_se(bus_gvariant_get_size("q") == 2);
assert_se(bus_gvariant_get_size("i") == 4);
assert_se(bus_gvariant_get_size("t") == 8);
assert_se(bus_gvariant_get_size("d") == 8);
assert_se(bus_gvariant_get_size("s") < 0);
assert_se(bus_gvariant_get_size("o") < 0);
assert_se(bus_gvariant_get_size("g") < 0);
assert_se(bus_gvariant_get_size("h") == 4);
assert_se(bus_gvariant_get_size("ay") < 0);
assert_se(bus_gvariant_get_size("v") < 0);
assert_se(bus_gvariant_get_size("(u)") == 4);
assert_se(bus_gvariant_get_size("(uuuuy)") == 20);
assert_se(bus_gvariant_get_size("(uusuuy)") < 0);
assert_se(bus_gvariant_get_size("a{ss}") < 0);
assert_se(bus_gvariant_get_size("((u)yyy(b(iiii)))") == 28);
assert_se(bus_gvariant_get_size("((u)yyy(b(iiivi)))") < 0);
assert_se(bus_gvariant_get_size("((b)(t))") == 16);
assert_se(bus_gvariant_get_size("((b)(b)(t))") == 16);
assert_se(bus_gvariant_get_size("(bt)") == 16);
assert_se(bus_gvariant_get_size("((t)(b))") == 16);
assert_se(bus_gvariant_get_size("(tb)") == 16);
assert_se(bus_gvariant_get_size("((b)(b))") == 2);
assert_se(bus_gvariant_get_size("((t)(t))") == 16);
}
TEST(bus_gvariant_get_alignment) {
assert_se(bus_gvariant_get_alignment("") == 1);
assert_se(bus_gvariant_get_alignment("()") == -EINVAL);
assert_se(bus_gvariant_get_alignment("y") == 1);
assert_se(bus_gvariant_get_alignment("b") == 1);
assert_se(bus_gvariant_get_alignment("u") == 4);
assert_se(bus_gvariant_get_alignment("s") == 1);
assert_se(bus_gvariant_get_alignment("o") == 1);
assert_se(bus_gvariant_get_alignment("g") == 1);
assert_se(bus_gvariant_get_alignment("v") == 8);
assert_se(bus_gvariant_get_alignment("h") == 4);
assert_se(bus_gvariant_get_alignment("i") == 4);
assert_se(bus_gvariant_get_alignment("t") == 8);
assert_se(bus_gvariant_get_alignment("x") == 8);
assert_se(bus_gvariant_get_alignment("q") == 2);
assert_se(bus_gvariant_get_alignment("n") == 2);
assert_se(bus_gvariant_get_alignment("d") == 8);
assert_se(bus_gvariant_get_alignment("ay") == 1);
assert_se(bus_gvariant_get_alignment("as") == 1);
assert_se(bus_gvariant_get_alignment("au") == 4);
assert_se(bus_gvariant_get_alignment("an") == 2);
assert_se(bus_gvariant_get_alignment("ans") == 2);
assert_se(bus_gvariant_get_alignment("ant") == 8);
assert_se(bus_gvariant_get_alignment("(ss)") == 1);
assert_se(bus_gvariant_get_alignment("(ssu)") == 4);
assert_se(bus_gvariant_get_alignment("a(ssu)") == 4);
assert_se(bus_gvariant_get_alignment("(u)") == 4);
assert_se(bus_gvariant_get_alignment("(uuuuy)") == 4);
assert_se(bus_gvariant_get_alignment("(uusuuy)") == 4);
assert_se(bus_gvariant_get_alignment("a{ss}") == 1);
assert_se(bus_gvariant_get_alignment("((u)yyy(b(iiii)))") == 4);
assert_se(bus_gvariant_get_alignment("((u)yyy(b(iiivi)))") == 8);
assert_se(bus_gvariant_get_alignment("((b)(t))") == 8);
assert_se(bus_gvariant_get_alignment("((b)(b)(t))") == 8);
assert_se(bus_gvariant_get_alignment("(bt)") == 8);
assert_se(bus_gvariant_get_alignment("((t)(b))") == 8);
assert_se(bus_gvariant_get_alignment("(tb)") == 8);
assert_se(bus_gvariant_get_alignment("((b)(b))") == 1);
assert_se(bus_gvariant_get_alignment("((t)(t))") == 8);
}
TEST_RET(marshal) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *n = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_free_ void *blob = NULL;
size_t sz;
int r;
r = sd_bus_open_user(&bus);
if (r < 0)
r = sd_bus_open_system(&bus);
if (r < 0)
return log_tests_skipped_errno(r, "Failed to connect to bus");
bus->message_version = 2; /* dirty hack to enable gvariant */
r = sd_bus_message_new_method_call(bus, &m, "a.service.name",
"/an/object/path/which/is/really/really/long/so/that/we/hit/the/eight/bit/boundary/by/quite/some/margin/to/test/this/stuff/that/it/really/works",
"an.interface.name", "AMethodName");
assert_se(r >= 0);
assert_cc(sizeof(struct bus_header) == 16);
assert_se(sd_bus_message_append(m,
"a(usv)", 3,
4711, "first-string-parameter", "(st)", "X", (uint64_t) 1111,
4712, "second-string-parameter", "(a(si))", 2, "Y", 5, "Z", 6,
4713, "third-string-parameter", "(uu)", 1, 2) >= 0);
assert_se(sd_bus_message_seal(m, 4711, 0) >= 0);
#if HAVE_GLIB
{
GVariant *v;
char *t;
#if !defined(GLIB_VERSION_2_36)
g_type_init();
#endif
v = g_variant_new_from_data(G_VARIANT_TYPE("(yyyyuta{tv})"), m->header, sizeof(struct bus_header) + m->fields_size, false, NULL, NULL);
assert_se(g_variant_is_normal_form(v));
t = g_variant_print(v, TRUE);
printf("%s\n", t);
g_free(t);
g_variant_unref(v);
v = g_variant_new_from_data(G_VARIANT_TYPE("(a(usv))"), m->body.data, m->user_body_size, false, NULL, NULL);
assert_se(g_variant_is_normal_form(v));
t = g_variant_print(v, TRUE);
printf("%s\n", t);
g_free(t);
g_variant_unref(v);
}
#endif
assert_se(sd_bus_message_dump(m, NULL, SD_BUS_MESSAGE_DUMP_WITH_HEADER) >= 0);
assert_se(bus_message_get_blob(m, &blob, &sz) >= 0);
#if HAVE_GLIB
{
GVariant *v;
char *t;
v = g_variant_new_from_data(G_VARIANT_TYPE("(yyyyuta{tv}v)"), blob, sz, false, NULL, NULL);
assert_se(g_variant_is_normal_form(v));
t = g_variant_print(v, TRUE);
printf("%s\n", t);
g_free(t);
g_variant_unref(v);
}
#endif
assert_se(bus_message_from_malloc(bus, blob, sz, NULL, 0, NULL, &n) >= 0);
blob = NULL;
assert_se(sd_bus_message_dump(n, NULL, SD_BUS_MESSAGE_DUMP_WITH_HEADER) >= 0);
m = sd_bus_message_unref(m);
assert_se(sd_bus_message_new_method_call(bus, &m, "a.x", "/a/x", "a.x", "Ax") >= 0);
assert_se(sd_bus_message_append(m, "as", 0) >= 0);
assert_se(sd_bus_message_seal(m, 4712, 0) >= 0);
assert_se(sd_bus_message_dump(m, NULL, SD_BUS_MESSAGE_DUMP_WITH_HEADER) >= 0);
return EXIT_SUCCESS;
}
DEFINE_TEST_MAIN(LOG_DEBUG);