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:
commit
1fef1773c0
@ -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',
|
||||
|
@ -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 = ({ \
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 },
|
||||
|
@ -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),
|
||||
|
@ -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',
|
||||
|
21
src/shared/varlink-idl-common.c
Normal file
21
src/shared/varlink-idl-common.c
Normal 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));
|
7
src/shared/varlink-idl-common.h
Normal file
7
src/shared/varlink-idl-common.h
Normal 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;
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user