1
0
mirror of https://github.com/systemd/systemd.git synced 2025-02-18 21:57:48 +03:00

Merge pull request #34703 from poettering/pidref-varlink

Serialize "PidRef" in a reasonable way in Varlink interfaces
This commit is contained in:
Lennart Poettering 2024-10-11 13:33:44 +02:00 committed by GitHub
commit 1fef1773c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 292 additions and 27 deletions

View File

@ -561,10 +561,10 @@ conf.set_quoted('LONG_MAX_STR', '@0@'.format(long_max))
decl_headers = '''
#include <dirent.h>
#include <uchar.h>
#include <sched.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sched.h>
#include <uchar.h>
'''
foreach decl : ['char16_t',

View File

@ -549,6 +549,7 @@ static inline uint64_t ALIGN_OFFSET_U64(uint64_t l, uint64_t ali) {
#define sizeof_field(struct_type, member) sizeof(((struct_type *) 0)->member)
#define endoffsetof_field(struct_type, member) (offsetof(struct_type, member) + sizeof_field(struct_type, member))
#define voffsetof(v, member) offsetof(typeof(v), member)
#define _FOREACH_ARRAY(i, array, num, m, end) \
for (typeof(array[0]) *i = (array), *end = ({ \

View File

@ -5,7 +5,9 @@
#include "in-addr-util.h"
#include "iovec-util.h"
#include "json-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
#include "string-util.h"
#include "user-util.h"
@ -144,3 +146,138 @@ int json_dispatch_path(const char *name, sd_json_variant *variant, sd_json_dispa
return 0;
}
int json_variant_new_pidref(sd_json_variant **ret, PidRef *pidref) {
sd_id128_t boot_id;
int r;
/* Turns a PidRef into a triplet of PID, pidfd inode nr, and the boot ID. The triplet should uniquely
* identify the process globally, and be good enough to turn back into a pidfd + PidRef */
if (!pidref_is_set(pidref))
return sd_json_variant_new_null(ret);
r = pidref_acquire_pidfd_id(pidref);
if (r < 0 && !ERRNO_IS_NEG_NOT_SUPPORTED(r) && r != -ENOMEDIUM)
return r;
if (pidref->fd_id > 0) {
/* If we have the pidfd inode number, also acquire the boot ID, to make things universally unique */
r = sd_id128_get_boot(&boot_id);
if (r < 0)
return r;
}
return sd_json_buildo(
ret,
SD_JSON_BUILD_PAIR_INTEGER("pid", pidref->pid),
SD_JSON_BUILD_PAIR_CONDITION(pidref->fd_id > 0, "pidfdId", SD_JSON_BUILD_INTEGER(pidref->fd_id)),
SD_JSON_BUILD_PAIR_CONDITION(pidref->fd_id > 0, "bootId", SD_JSON_BUILD_ID128(boot_id)));
}
int json_dispatch_pidref(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
PidRef *p = ASSERT_PTR(userdata);
int r;
assert(variant);
/* Turns a JSON PID triplet back into a PidRef, i.e. the reverse of json_variant_new_pidref()
* above. If SD_JSON_STRICT is set this will acquire a pidfd for the process, and validate that the
* auxiliary fields match it. Otherwise, this will just store the pid and the pidfd inode number (the
* latter not if the provided boot id differs from the local one), and not attempt to get a pidfd for
* it, or authenticate it. */
if (sd_json_variant_is_null(variant)) {
pidref_done(p);
return 0;
}
struct {
uint64_t pid, fd_id;
sd_id128_t boot_id;
} data = {};
if (sd_json_variant_is_integer(variant))
/* Permit a simple classic integer based format */
data.pid = sd_json_variant_integer(variant);
else if (sd_json_variant_is_string(variant)) {
/* As usual, allow integers be encoded as strings too */
r = safe_atou64(sd_json_variant_string(variant), &data.pid);
if (r < 0)
return json_log(variant, flags, r, "JSON field '%s' is not a numeric PID.", strna(name));
} else if (sd_json_variant_is_object(variant)) {
static const sd_json_dispatch_field dispatch_table[] = {
{ "pid", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, voffsetof(data, pid), SD_JSON_MANDATORY },
{ "pidfdId", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, voffsetof(data, fd_id), 0 },
{ "bootId", SD_JSON_VARIANT_STRING, sd_json_dispatch_id128, voffsetof(data, boot_id), 0 },
{}
};
r = sd_json_dispatch(variant, dispatch_table, flags, &data);
if (r < 0)
return r;
} else
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is neither a numeric PID nor a PID object.", strna(name));
/* Before casting the 64bit data.pid field to pid_t, let's ensure it fits the pid_t range. */
if (data.pid > PID_T_MAX || !pid_is_valid(data.pid))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' does not contain a valid PID.", strna(name));
int local_boot_id = -1; /* tristate */
if (!sd_id128_is_null(data.boot_id)) {
sd_id128_t my_boot_id;
r = sd_id128_get_boot(&my_boot_id);
if (r < 0) {
json_log(variant, flags | (FLAGS_SET(flags, SD_JSON_STRICT) ? 0 : SD_JSON_DEBUG), r, "Unable to get local boot ID to validate JSON field '%s': %m", strna(name));
if (FLAGS_SET(flags, SD_JSON_STRICT))
return r;
} else {
local_boot_id = sd_id128_equal(data.boot_id, my_boot_id);
if (!local_boot_id) {
json_log(variant, flags | (FLAGS_SET(flags, SD_JSON_STRICT) ? 0 : SD_JSON_DEBUG), 0, "JSON field '%s' refers to non-local PID.", strna(name));
if (FLAGS_SET(flags, SD_JSON_STRICT))
return -ESRCH;
}
}
}
_cleanup_(pidref_done) PidRef np = PIDREF_NULL;
if (local_boot_id != 0) {
/* Try to acquire a pidfd unless this is definitely not a local PID */
r = pidref_set_pid(&np, data.pid);
if (r < 0) {
json_log(variant, flags | (FLAGS_SET(flags, SD_JSON_STRICT) ? 0 : SD_JSON_DEBUG), r, "Unable to get fd for PID in JSON field '%s': %m", strna(name));
if (FLAGS_SET(flags, SD_JSON_STRICT))
return r;
}
}
/* If the the PID is dead or we otherwise can't get a pidfd of it, then store at least the PID number */
if (!pidref_is_set(&np))
np = PIDREF_MAKE_FROM_PID(data.pid);
/* If the pidfd inode nr is specified, validate it or at least state */
if (data.fd_id > 0) {
if (np.fd >= 0) {
r = pidref_acquire_pidfd_id(&np);
if (r < 0 && !ERRNO_IS_NOT_SUPPORTED(r))
return json_log(variant, flags, r, "Unable to get pidfd ID to validate JSON field '%s': %m", strna(name));
if (data.fd_id != np.fd_id) {
json_log(variant, flags | (FLAGS_SET(flags, SD_JSON_STRICT) ? 0 : SD_JSON_DEBUG), 0, "JSON field '%s' references PID with non-matching inode number.", strna(name));
if (FLAGS_SET(flags, SD_JSON_STRICT))
return -ESRCH;
}
} else if (local_boot_id != 0) {
json_log(variant, flags|SD_JSON_DEBUG, 0, "Not validating PID inode number on JSON field '%s', because operating without pidfd.", strna(name));
np.fd_id = data.fd_id;
}
}
pidref_done(p);
*p = TAKE_PIDREF(np);
return 0;
}

View File

@ -6,6 +6,7 @@
#include "sd-json.h"
#include "macro.h"
#include "pidref.h"
#define JSON_VARIANT_REPLACE(v, q) \
do { \
@ -112,6 +113,7 @@ int json_dispatch_user_group_name(const char *name, sd_json_variant *variant, sd
int json_dispatch_const_user_group_name(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
int json_dispatch_in_addr(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
int json_dispatch_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
int json_dispatch_pidref(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
static inline int json_variant_unbase64_iovec(sd_json_variant *v, struct iovec *ret) {
return sd_json_variant_unbase64(v, ret ? &ret->iov_base : NULL, ret ? &ret->iov_len : NULL);
@ -144,6 +146,7 @@ enum {
_JSON_BUILD_DUAL_TIMESTAMP,
_JSON_BUILD_RATELIMIT,
_JSON_BUILD_TRISTATE,
_JSON_BUILD_PIDREF,
_JSON_BUILD_PAIR_INTEGER_NON_ZERO,
_JSON_BUILD_PAIR_INTEGER_NON_NEGATIVE,
@ -168,6 +171,7 @@ enum {
_JSON_BUILD_PAIR_HEX_NON_EMPTY,
_JSON_BUILD_PAIR_OCTESCAPE_NON_EMPTY,
_JSON_BUILD_PAIR_TRISTATE_NON_NULL,
_JSON_BUILD_PAIR_PIDREF_NON_NULL,
_SD_JSON_BUILD_REALLYMAX,
};
@ -187,6 +191,7 @@ enum {
#define JSON_BUILD_DUAL_TIMESTAMP(t) _JSON_BUILD_DUAL_TIMESTAMP, (dual_timestamp*) { t }
#define JSON_BUILD_RATELIMIT(rl) _JSON_BUILD_RATELIMIT, (const RateLimit*) { rl }
#define JSON_BUILD_TRISTATE(i) _JSON_BUILD_TRISTATE, (int) { i }
#define JSON_BUILD_PIDREF(p) _JSON_BUILD_PIDREF, (const PidRef*) { p }
#define JSON_BUILD_PAIR_INTEGER_NON_ZERO(name, i) _JSON_BUILD_PAIR_INTEGER_NON_ZERO, (const char*) { name }, (int64_t) { i }
#define JSON_BUILD_PAIR_INTEGER_NON_NEGATIVE(name, i) _JSON_BUILD_PAIR_INTEGER_NON_NEGATIVE, (const char*) { name }, (int64_t) { i }
@ -210,6 +215,7 @@ enum {
#define JSON_BUILD_PAIR_HEX_NON_EMPTY(name, v, n) _JSON_BUILD_PAIR_HEX_NON_EMPTY, (const char*) { name }, (const void*) { v }, (size_t) { n }
#define JSON_BUILD_PAIR_OCTESCAPE_NON_EMPTY(name, v, n) _JSON_BUILD_PAIR_HEX_NON_EMPTY, (const char*) { name }, (const void*) { v }, (size_t) { n }
#define JSON_BUILD_PAIR_TRISTATE_NON_NULL(name, i) _JSON_BUILD_PAIR_TRISTATE_NON_NULL, (const char*) { name }, (int) { i }
#define JSON_BUILD_PAIR_PIDREF_NON_NULL(name, p) _JSON_BUILD_PAIR_PIDREF_NON_NULL, (const char*) { name }, (const PidRef*) { p }
#define JSON_BUILD_PAIR_IOVEC_BASE64(name, iov) SD_JSON_BUILD_PAIR(name, JSON_BUILD_IOVEC_BASE64(iov))
#define JSON_BUILD_PAIR_IOVEC_HEX(name, iov) SD_JSON_BUILD_PAIR(name, JSON_BUILD_IOVEC_HEX(iov))
@ -223,3 +229,6 @@ enum {
#define JSON_BUILD_PAIR_DUAL_TIMESTAMP(name, t) SD_JSON_BUILD_PAIR(name, JSON_BUILD_DUAL_TIMESTAMP(t))
#define JSON_BUILD_PAIR_RATELIMIT(name, rl) SD_JSON_BUILD_PAIR(name, JSON_BUILD_RATELIMIT(rl))
#define JSON_BUILD_PAIR_TRISTATE(name, i) SD_JSON_BUILD_PAIR(name, JSON_BUILD_TRISTATE(i))
#define JSON_BUILD_PAIR_PIDREF(name, p) SD_JSON_BUILD_PAIR(name, JSON_BUILD_PIDREF(p))
int json_variant_new_pidref(sd_json_variant **ret, PidRef *pidref);

View File

@ -4196,6 +4196,34 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
break;
}
case _JSON_BUILD_PIDREF: {
PidRef *pidref;
if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
r = -EINVAL;
goto finish;
}
pidref = va_arg(ap, PidRef*);
if (current->n_suppress == 0) {
r = json_variant_new_pidref(&add, pidref);
if (r < 0)
goto finish;
}
n_subtract = 1;
if (current->expect == EXPECT_TOPLEVEL)
current->expect = EXPECT_END;
else if (current->expect == EXPECT_OBJECT_VALUE)
current->expect = EXPECT_OBJECT_KEY;
else
assert(current->expect == EXPECT_ARRAY_ELEMENT);
break;
}
case _JSON_BUILD_TRISTATE: {
int tristate;
@ -4771,6 +4799,34 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
break;
}
case _JSON_BUILD_PAIR_PIDREF_NON_NULL: {
PidRef *p;
const char *n;
if (current->expect != EXPECT_OBJECT_KEY) {
r = -EINVAL;
goto finish;
}
n = va_arg(ap, const char*);
p = va_arg(ap, PidRef*);
if (pidref_is_set(p) && current->n_suppress == 0) {
r = sd_json_variant_new_string(&add, n);
if (r < 0)
goto finish;
r = json_variant_new_pidref(&add_more, p);
if (r < 0)
goto finish;
}
n_subtract = 2; /* we generated two items */
current->expect = EXPECT_OBJECT_KEY;
break;
}
case _JSON_BUILD_PAIR_CALLBACK_NON_NULL: {
sd_json_build_callback_t cb;
void *userdata;

View File

@ -45,25 +45,16 @@ static int machine_name(const char *name, sd_json_variant *variant, sd_json_disp
static int machine_leader(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
PidRef *leader = ASSERT_PTR(userdata);
_cleanup_(pidref_done) PidRef temp = PIDREF_NULL;
uint64_t k;
int r;
if (!sd_json_variant_is_unsigned(variant))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an integer.", strna(name));
r = json_dispatch_pidref(name, variant, flags, &temp);
if (r < 0)
return r;
k = sd_json_variant_unsigned(variant);
if (k > PID_T_MAX || !pid_is_valid(k))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid PID.", strna(name));
if (k == 1)
if (temp.pid == 1) /* refuse PID 1 */
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid leader PID.", strna(name));
r = pidref_set_pid(&temp, k);
if (r < 0)
return json_log(variant, flags, r, "Failed to pin process " PID_FMT ": %m", leader->pid);
pidref_done(leader);
*leader = TAKE_PIDREF(temp);
return 0;
@ -133,7 +124,7 @@ int vl_method_register(sd_varlink *link, sd_json_variant *parameters, sd_varlink
{ "id", SD_JSON_VARIANT_STRING, sd_json_dispatch_id128, offsetof(Machine, id), 0 },
{ "service", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(Machine, service), 0 },
{ "class", SD_JSON_VARIANT_STRING, dispatch_machine_class, offsetof(Machine, class), SD_JSON_MANDATORY },
{ "leader", SD_JSON_VARIANT_UNSIGNED, machine_leader, offsetof(Machine, leader), 0 },
{ "leader", _SD_JSON_VARIANT_TYPE_INVALID, machine_leader, offsetof(Machine, leader), SD_JSON_STRICT },
{ "rootDirectory", SD_JSON_VARIANT_STRING, json_dispatch_path, offsetof(Machine, root_directory), 0 },
{ "ifIndices", SD_JSON_VARIANT_ARRAY, machine_ifindices, 0, 0 },
{ "vSockCid", _SD_JSON_VARIANT_TYPE_INVALID, machine_cid, offsetof(Machine, vsock_cid), 0 },

View File

@ -404,7 +404,7 @@ static int list_machine_one(sd_varlink *link, Machine *m, bool more) {
JSON_BUILD_PAIR_STRING_NON_EMPTY("service", m->service),
JSON_BUILD_PAIR_STRING_NON_EMPTY("rootDirectory", m->root_directory),
JSON_BUILD_PAIR_STRING_NON_EMPTY("unit", m->unit),
SD_JSON_BUILD_PAIR_CONDITION(pidref_is_set(&m->leader), "leader", SD_JSON_BUILD_UNSIGNED(m->leader.pid)),
SD_JSON_BUILD_PAIR_CONDITION(pidref_is_set(&m->leader), "leader", JSON_BUILD_PIDREF(&m->leader)),
SD_JSON_BUILD_PAIR_CONDITION(dual_timestamp_is_set(&m->timestamp), "timestamp", JSON_BUILD_DUAL_TIMESTAMP(&m->timestamp)),
SD_JSON_BUILD_PAIR_CONDITION(m->vsock_cid != VMADDR_CID_ANY, "vSockCid", SD_JSON_BUILD_UNSIGNED(m->vsock_cid)),
JSON_BUILD_PAIR_STRING_NON_EMPTY("sshAddress", m->ssh_address),

View File

@ -177,6 +177,7 @@ shared_sources = files(
'user-record.c',
'userdb-dropin.c',
'userdb.c',
'varlink-idl-common.c',
'varlink-io.systemd.BootControl.c',
'varlink-io.systemd.Credentials.c',
'varlink-io.systemd.Hostname.c',

View File

@ -0,0 +1,21 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-varlink-idl.h"
#include "varlink-idl-common.h"
SD_VARLINK_DEFINE_STRUCT_TYPE(
Timestamp,
SD_VARLINK_FIELD_COMMENT("Timestamp in µs in the CLOCK_REALTIME clock (wallclock)"),
SD_VARLINK_DEFINE_FIELD(realtime, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Timestamp in µs in the CLOCK_MONOTONIC clock"),
SD_VARLINK_DEFINE_FIELD(monotonic, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
SD_VARLINK_DEFINE_STRUCT_TYPE(
ProcessId,
SD_VARLINK_FIELD_COMMENT("Numeric UNIX PID value"),
SD_VARLINK_DEFINE_FIELD(pid, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("64bit inode number of pidfd if known"),
SD_VARLINK_DEFINE_FIELD(pidfdId, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Boot ID of the system the inode number belongs to"),
SD_VARLINK_DEFINE_FIELD(bootId, SD_VARLINK_INT, SD_VARLINK_NULLABLE));

View File

@ -0,0 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-varlink-idl.h"
extern const sd_varlink_symbol vl_type_Timestamp;
extern const sd_varlink_symbol vl_type_ProcessId;

View File

@ -3,6 +3,7 @@
#include "sd-varlink-idl.h"
#include "bus-polkit.h"
#include "varlink-idl-common.h"
#include "varlink-io.systemd.Machine.h"
#define VARLINK_DEFINE_MACHINE_LOOKUP_AND_POLKIT_INPUT_FIELDS \
@ -18,7 +19,7 @@ static SD_VARLINK_DEFINE_METHOD(
SD_VARLINK_DEFINE_INPUT(id, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_INPUT(service, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_INPUT(class, SD_VARLINK_STRING, 0),
SD_VARLINK_DEFINE_INPUT(leader, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_INPUT_BY_TYPE(leader, ProcessId, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_INPUT(rootDirectory, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_INPUT(ifIndices, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_INPUT(vSockCid, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
@ -28,13 +29,6 @@ static SD_VARLINK_DEFINE_METHOD(
SD_VARLINK_DEFINE_INPUT(allocateUnit, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
VARLINK_DEFINE_POLKIT_INPUT);
static SD_VARLINK_DEFINE_STRUCT_TYPE(
Timestamp,
SD_VARLINK_FIELD_COMMENT("Timestamp in µs in the CLOCK_REALTIME clock (wallclock)"),
SD_VARLINK_DEFINE_FIELD(realtime, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Timestamp in µs in the CLOCK_MONOTONIC clock"),
SD_VARLINK_DEFINE_FIELD(monotonic, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD(
Unregister,
VARLINK_DEFINE_MACHINE_LOOKUP_AND_POLKIT_INPUT_FIELDS);
@ -64,7 +58,7 @@ static SD_VARLINK_DEFINE_METHOD_FULL(
SD_VARLINK_FIELD_COMMENT("The class of this machine"),
SD_VARLINK_DEFINE_OUTPUT(class, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Leader process PID of this machine"),
SD_VARLINK_DEFINE_OUTPUT(leader, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(leader, ProcessId, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Root directory of this machine, if known, relative to host file system"),
SD_VARLINK_DEFINE_OUTPUT(rootDirectory, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The service manager unit this machine resides in"),
@ -84,6 +78,8 @@ static SD_VARLINK_DEFINE_ERROR(MachineExists);
SD_VARLINK_DEFINE_INTERFACE(
io_systemd_Machine,
"io.systemd.Machine",
SD_VARLINK_SYMBOL_COMMENT("An object for referencing UNIX processes"),
&vl_type_ProcessId,
SD_VARLINK_SYMBOL_COMMENT("A timestamp object consisting of both CLOCK_REALTIME and CLOCK_MONOTONIC timestamps"),
&vl_type_Timestamp,
&vl_method_Register,

View File

@ -1264,4 +1264,47 @@ TEST(parse_continue) {
assert_se(sd_json_parse_with_source_continue(&p, "piff", /* flags= */ 0, &x, &line, &column) == -EINVAL);
}
TEST(pidref) {
_cleanup_(pidref_done) PidRef myself = PIDREF_NULL, pid1 = PIDREF_NULL;
assert_se(pidref_set_pid(&myself, 0) >= 0);
assert_se(pidref_set_pid(&pid1, 1) >= 0);
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
assert_se(sd_json_buildo(&v,
JSON_BUILD_PAIR_PIDREF("myself", &myself),
JSON_BUILD_PAIR_PIDREF("pid1", &pid1)) >= 0);
sd_json_variant_dump(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
struct {
PidRef myself, pid1;
} data = {
.myself = PIDREF_NULL,
.pid1 = PIDREF_NULL,
};
assert_se(sd_json_dispatch(
v,
(const sd_json_dispatch_field[]) {
{ "myself", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_pidref, voffsetof(data, myself), 0 },
{ "pid1", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_pidref, voffsetof(data, pid1), 0 },
{},
},
/* flags= */ 0,
&data) >= 0);
assert_se(pidref_equal(&myself, &data.myself));
assert_se(pidref_equal(&pid1, &data.pid1));
assert_se(!pidref_equal(&myself, &data.pid1));
assert_se(!pidref_equal(&pid1, &data.myself));
assert_se((myself.fd_id > 0) == (data.myself.fd_id > 0));
assert_se((pid1.fd_id > 0) == (data.pid1.fd_id > 0));
pidref_done(&data.myself);
pidref_done(&data.pid1);
}
DEFINE_TEST_MAIN(LOG_DEBUG);

View File

@ -14,6 +14,7 @@
#include "varlink-io.systemd.Credentials.h"
#include "varlink-io.systemd.Import.h"
#include "varlink-io.systemd.Journal.h"
#include "varlink-io.systemd.Machine.h"
#include "varlink-io.systemd.ManagedOOM.h"
#include "varlink-io.systemd.MountFileSystem.h"
#include "varlink-io.systemd.NamespaceResource.h"
@ -187,6 +188,8 @@ TEST(parse_format) {
print_separator();
test_parse_format_one(&vl_interface_io_systemd_Import);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_Machine);
print_separator();
test_parse_format_one(&vl_interface_xyz_test);
}

View File

@ -251,7 +251,7 @@ varlinkctl --more call /run/systemd/machine/io.systemd.Machine io.systemd.Machin
varlinkctl --more call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{}' | grep '.host'
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{"name":"long-running"}'
pid=$(varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{"name":"long-running"}' | jq '.leader')
pid=$(varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{"name":"long-running"}' | jq '.leader.pid')
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{"name":"long-running"}' >/tmp/expected
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List "{\"pid\":$pid}" >/tmp/got
diff -u /tmp/expected /tmp/got