1
0
mirror of https://github.com/systemd/systemd.git synced 2024-10-26 08:55:40 +03:00
This commit is contained in:
Yu Watanabe 2024-10-25 21:23:57 +02:00 committed by GitHub
commit 414251d8b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 145 additions and 52 deletions

View File

@ -266,7 +266,7 @@ static bool env_entry_has_name(const char *entry, const char *name) {
return *t == '=';
}
char **strv_env_delete(char **x, size_t n_lists, ...) {
char** strv_env_delete(char **x, size_t n_lists, ...) {
size_t n, i = 0;
_cleanup_strv_free_ char **t = NULL;
va_list ap;
@ -564,7 +564,30 @@ char* strv_env_pairs_get(char **l, const char *name) {
return result;
}
char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
int strv_env_get_merged(char **l, char ***ret) {
_cleanup_strv_free_ char **v = NULL;
size_t n = 0;
int r;
assert(ret);
STRV_FOREACH_PAIR(key, value, l) {
char *s = NULL;
s = strjoin(*key, "=", *value);
if (!s)
return -ENOMEM;
r = strv_consume_with_size(&v, &n, s);
if (r < 0)
return r;
}
*ret = TAKE_PTR(v);
return 0;
}
char** strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
int k = 0;
STRV_FOREACH(p, e) {

View File

@ -34,14 +34,14 @@ int replace_env_argv(char **argv, char **env, char ***ret, char ***ret_unset_var
bool strv_env_is_valid(char **e);
#define strv_env_clean(l) strv_env_clean_with_callback(l, NULL, NULL)
char **strv_env_clean_with_callback(char **l, void (*invalid_callback)(const char *p, void *userdata), void *userdata);
char** strv_env_clean_with_callback(char **l, void (*invalid_callback)(const char *p, void *userdata), void *userdata);
bool strv_env_name_is_valid(char **l);
bool strv_env_name_or_assignment_is_valid(char **l);
char** _strv_env_merge(char **first, ...);
#define strv_env_merge(first, ...) _strv_env_merge(first, __VA_ARGS__, POINTER_MAX)
char **strv_env_delete(char **x, size_t n_lists, ...); /* New copy */
char** strv_env_delete(char **x, size_t n_lists, ...); /* New copy */
char** strv_env_unset(char **l, const char *p); /* In place ... */
char** strv_env_unset_many_internal(char **l, ...) _sentinel_;
@ -60,6 +60,7 @@ static inline char* strv_env_get(char * const *x, const char *n) {
}
char* strv_env_pairs_get(char **l, const char *name) _pure_;
int strv_env_get_merged(char **l, char ***ret);
int getenv_bool(const char *p);
int secure_getenv_bool(const char *p);

View File

@ -998,6 +998,7 @@ global:
sd_varlink_invoke;
sd_varlink_invokeb;
sd_varlink_is_idle;
sd_varlink_is_processing_method;
sd_varlink_notify;
sd_varlink_notifyb;
sd_varlink_observe;

View File

@ -157,6 +157,7 @@ enum {
_JSON_BUILD_PAIR_FINITE_USEC,
_JSON_BUILD_PAIR_STRING_NON_EMPTY,
_JSON_BUILD_PAIR_STRV_NON_EMPTY,
_JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY,
_JSON_BUILD_PAIR_VARIANT_NON_NULL,
/* _SD_JSON_BUILD_PAIR_VARIANT_ARRAY_NON_EMPTY, */
_JSON_BUILD_PAIR_BYTE_ARRAY_NON_EMPTY,
@ -204,6 +205,7 @@ enum {
#define JSON_BUILD_PAIR_FINITE_USEC(name, u) _JSON_BUILD_PAIR_FINITE_USEC, (const char*) { name }, (usec_t) { u }
#define JSON_BUILD_PAIR_STRING_NON_EMPTY(name, s) _JSON_BUILD_PAIR_STRING_NON_EMPTY, (const char*) { name }, (const char*) { s }
#define JSON_BUILD_PAIR_STRV_NON_EMPTY(name, l) _JSON_BUILD_PAIR_STRV_NON_EMPTY, (const char*) { name }, (char**) { l }
#define JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY(name, l) _JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY, (const char*) { name }, (char**) { l }
#define JSON_BUILD_PAIR_VARIANT_NON_NULL(name, v) _JSON_BUILD_PAIR_VARIANT_NON_NULL, (const char*) { name }, (sd_json_variant*) { v }
#define JSON_BUILD_PAIR_BYTE_ARRAY_NON_EMPTY(name, v, n) _JSON_BUILD_PAIR_BYTE_ARRAY_NON_EMPTY, (const char*) { name }, (const void*) { v }, (size_t) { n }
#define JSON_BUILD_PAIR_IN4_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_IN4_ADDR_NON_NULL, (const char*) { name }, (const struct in_addr*) { v }

View File

@ -11,6 +11,7 @@
#include "alloc-util.h"
#include "ansi-color.h"
#include "env-util.h"
#include "errno-util.h"
#include "escape.h"
#include "ether-addr-util.h"
@ -3867,22 +3868,13 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
l = va_arg(ap, char **);
_cleanup_strv_free_ char **el = NULL;
STRV_FOREACH_PAIR(x, y, l) {
char *n = NULL;
if (current->n_suppress == 0) {
_cleanup_strv_free_ char **el = NULL;
n = strjoin(*x, "=", *y);
if (!n) {
r = -ENOMEM;
goto finish;
}
r = strv_consume(&el, n);
r = strv_env_get_merged(l, &el);
if (r < 0)
goto finish;
}
if (current->n_suppress == 0) {
r = sd_json_variant_new_array_strv(&add, el);
if (r < 0)
goto finish;
@ -4541,7 +4533,8 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
break;
}
case _JSON_BUILD_PAIR_STRV_NON_EMPTY: {
case _JSON_BUILD_PAIR_STRV_NON_EMPTY:
case _JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY: {
const char *n;
char **l;
@ -4554,11 +4547,19 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
l = va_arg(ap, char **);
if (!strv_isempty(l) && current->n_suppress == 0) {
_cleanup_strv_free_ char **el = NULL;
if (command == _JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY) {
r = strv_env_get_merged(l, &el);
if (r < 0)
goto finish;
}
r = sd_json_variant_new_string(&add, n);
if (r < 0)
goto finish;
r = sd_json_variant_new_array_strv(&add_more, l);
r = sd_json_variant_new_array_strv(&add_more, el ?: l);
if (r < 0)
goto finish;
}

View File

@ -1655,6 +1655,13 @@ _public_ int sd_varlink_is_idle(sd_varlink *v) {
return IN_SET(v->state, VARLINK_DISCONNECTED, VARLINK_IDLE_CLIENT, VARLINK_IDLE_SERVER);
}
_public_ int sd_varlink_is_processing_method(sd_varlink *v) {
if (!v)
return false;
return IN_SET(v->state, VARLINK_PROCESSING_METHOD, VARLINK_PROCESSING_METHOD_MORE, VARLINK_PROCESSING_METHOD_ONEWAY);
}
_public_ int sd_varlink_get_fd(sd_varlink *v) {
assert_return(v, -EINVAL);

View File

@ -392,56 +392,52 @@ static int vl_method_get_memberships(sd_varlink *link, sd_json_variant *paramete
}
static int json_build_local_addresses(const struct local_address *addresses, size_t n_addresses, sd_json_variant **ret) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *array = NULL;
int r;
if (n_addresses == 0)
return 0;
assert(addresses);
assert(addresses || n_addresses == 0);
assert(ret);
FOREACH_ARRAY(a, addresses, n_addresses) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *entry = NULL;
r = sd_json_buildo(
&entry,
r = sd_json_variant_append_arraybo(
&array,
JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("ifindex", a->ifindex),
SD_JSON_BUILD_PAIR_INTEGER("family", a->family),
SD_JSON_BUILD_PAIR_BYTE_ARRAY("address", &a->address.bytes, FAMILY_ADDRESS_SIZE(a->family)));
if (r < 0)
return r;
r = sd_json_variant_append_array(ret, entry);
if (r < 0)
return r;
}
*ret = TAKE_PTR(array);
return 0;
}
static int list_machine_one_and_maybe_read_metadata(sd_varlink *link, Machine *m, bool more, AcquireMetadata am) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *addr_array = NULL;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *addr_array = NULL;
_cleanup_strv_free_ char **os_release = NULL;
uid_t shift = UID_INVALID;
int r, n = 0;
int r;
assert(link);
assert(m);
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
if (!sd_varlink_is_processing_method(link))
return 0;
if (should_acquire_metadata(am)) {
_cleanup_free_ struct local_address *addresses = NULL;
n = machine_get_addresses(m, &addresses);
if (n < 0 && am == ACQUIRE_METADATA_GRACEFUL)
log_debug_errno(n, "Failed to get address (graceful mode), ignoring: %m");
else if (n == -ENONET)
r = machine_get_addresses(m, &addresses);
if (r < 0 && am == ACQUIRE_METADATA_GRACEFUL)
log_debug_errno(r, "Failed to get address (graceful mode), ignoring: %m");
else if (r == -ENONET)
return sd_varlink_error(link, "io.systemd.Machine.NoPrivateNetworking", NULL);
else if (ERRNO_IS_NEG_NOT_SUPPORTED(n))
else if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
return sd_varlink_error(link, "io.systemd.Machine.NotAvailable", NULL);
else if (n < 0)
return log_debug_errno(n, "Failed to get addresses: %m");
else if (r < 0)
return log_debug_errno(r, "Failed to get addresses: %m");
else {
r = json_build_local_addresses(addresses, n, &addr_array);
r = json_build_local_addresses(addresses, r, &addr_array);
if (r < 0)
return r;
}
@ -477,11 +473,11 @@ static int list_machine_one_and_maybe_read_metadata(sd_varlink *link, Machine *m
JSON_BUILD_PAIR_STRING_NON_EMPTY("unit", m->unit),
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_UNSIGNED_NOT_EQUAL("vSockCid", m->vsock_cid, VMADDR_CID_ANY),
JSON_BUILD_PAIR_STRING_NON_EMPTY("sshAddress", m->ssh_address),
JSON_BUILD_PAIR_STRING_NON_EMPTY("sshPrivateKeyPath", m->ssh_private_key_path),
SD_JSON_BUILD_PAIR_CONDITION(n > 0, "addresses", SD_JSON_BUILD_VARIANT(addr_array)),
SD_JSON_BUILD_PAIR_CONDITION(!strv_isempty(os_release), "OSRelease", JSON_BUILD_STRV_ENV_PAIR(os_release)),
JSON_BUILD_PAIR_VARIANT_NON_NULL("addresses", addr_array),
JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY("OSRelease", os_release),
JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("UIDShift", shift, UID_INVALID));
if (r < 0)
return r;
@ -517,7 +513,6 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl
Manager *m = ASSERT_PTR(userdata);
_cleanup_(machine_lookup_parameters_done) MachineLookupParameters p = {
.pidref = PIDREF_NULL,
.acquire_metadata = ACQUIRE_METADATA_NO,
};
Machine *machine;
@ -604,6 +599,9 @@ static int list_image_one_and_maybe_read_metadata(sd_varlink *link, Image *image
assert(link);
assert(image);
if (!sd_varlink_is_processing_method(link))
return 0;
if (should_acquire_metadata(am) && !image->metadata_valid) {
r = image_read_metadata(image, &image_policy_container);
if (r < 0 && am != ACQUIRE_METADATA_GRACEFUL)
@ -635,8 +633,8 @@ static int list_image_one_and_maybe_read_metadata(sd_varlink *link, Image *image
&v,
JSON_BUILD_PAIR_STRING_NON_EMPTY("hostname", image->hostname),
SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(image->machine_id), "machineId", SD_JSON_BUILD_ID128(image->machine_id)),
SD_JSON_BUILD_PAIR_CONDITION(!strv_isempty(image->machine_info), "machineInfo", JSON_BUILD_STRV_ENV_PAIR(image->machine_info)),
SD_JSON_BUILD_PAIR_CONDITION(!strv_isempty(image->os_release), "OSRelease", JSON_BUILD_STRV_ENV_PAIR(image->os_release)));
JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY("machineInfo", image->machine_info),
JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY("OSRelease", image->os_release));
if (r < 0)
return r;
}
@ -651,7 +649,7 @@ static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters,
struct params {
const char *image_name;
AcquireMetadata acquire_metadata;
} p = { .acquire_metadata = ACQUIRE_METADATA_NO };
} p = {};
int r;
static const sd_json_dispatch_field dispatch_table[] = {

View File

@ -107,6 +107,7 @@ int sd_varlink_process(sd_varlink *v);
int sd_varlink_wait(sd_varlink *v, uint64_t timeout);
int sd_varlink_is_idle(sd_varlink *v);
int sd_varlink_is_processing_method(sd_varlink *v);
int sd_varlink_flush(sd_varlink *v);
int sd_varlink_close(sd_varlink *v);

View File

@ -581,4 +581,15 @@ TEST(getenv_path_list) {
assert_se(unsetenv("TEST_GETENV_PATH_LIST") >= 0);
}
TEST(strv_env_get_merged) {
char **l = STRV_MAKE("ONE", "1", "TWO", "2", "THREE", "3", "FOUR", "4", "FIVE", "5"),
**expected = STRV_MAKE("ONE=1", "TWO=2", "THREE=3", "FOUR=4", "FIVE=5");
_cleanup_strv_free_ char **m = NULL;
ASSERT_OK(strv_env_get_merged(NULL, &m));
ASSERT_NULL(m);
ASSERT_OK(strv_env_get_merged(l, &m));
ASSERT_TRUE(strv_equal(m, expected));
}
DEFINE_TEST_MAIN(LOG_DEBUG);

View File

@ -39,10 +39,10 @@ cat >/var/lib/machines/long-running/sbin/init <<\EOF
PID=0
trap "touch /terminate; kill $PID" RTMIN+3
trap "touch /poweroff" RTMIN+4
trap "touch /reboot" INT
trap "touch /trap" TRAP
trap 'touch /terminate; kill 0' RTMIN+3
trap 'touch /poweroff' RTMIN+4
trap 'touch /reboot' INT
trap 'touch /trap' TRAP
trap 'kill $PID' EXIT
# We need to wait for the sleep process asynchronously in order to allow
@ -304,11 +304,59 @@ varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Unreg
# test io.systemd.Machine.List with addresses, OSRelease, and UIDShift fields
create_dummy_container "/var/lib/machines/container-without-os-release"
cat >>/var/lib/machines/container-without-os-release/sbin/init <<\EOF
ip link add hoge type dummy
ip link set hoge up
ip address add 192.0.2.1/24 dev hoge
PID=0
trap 'kill 0' RTMIN+3
trap 'kill $PID' EXIT
# We need to wait for the sleep process asynchronously in order to allow
# bash to process signals
sleep infinity &
# notify that the process is ready
touch /ready
PID=$!
while :; do
wait || :
done
EOF
machinectl start "container-without-os-release"
timeout 30 bash -c "until test -e /var/lib/machines/container-without-os-release/ready; do sleep .5; done"
rm -f /var/lib/machines/container-without-os-release/etc/os-release /var/lib/machines/container-without-os-release/usr/lib/os-release
(! varlinkctl --more call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{"name": "container-without-os-release", "acquireMetadata": "yes"}')
varlinkctl --more call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{"name": "container-without-os-release", "acquireMetadata": "graceful"}'
output=$(varlinkctl --more call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{"name": "container-without-os-release", "acquireMetadata": "graceful"}')
assert_eq "$(echo "$output" | jq --seq .name | tr -d \\036)" '"container-without-os-release"'
assert_eq "$(echo "$output" | jq --seq .class | tr -d \\036)" '"container"'
assert_eq "$(echo "$output" | jq --seq .service | tr -d \\036)" '"systemd-nspawn"'
assert_eq "$(echo "$output" | jq --seq .rootDirectory | tr -d \\036)" '"/var/lib/machines/container-without-os-release"'
assert_eq "$(echo "$output" | jq --seq .unit | tr -d \\036)" '"systemd-nspawn@container-without-os-release.service"'
assert_eq "$(echo "$output" | jq --seq .addresses[0].family | tr -d \\036)" '2'
assert_eq "$(echo "$output" | jq --seq .addresses[0].address[0] | tr -d \\036)" '192'
assert_eq "$(echo "$output" | jq --seq .addresses[0].address[1] | tr -d \\036)" '0'
assert_eq "$(echo "$output" | jq --seq .addresses[0].address[2] | tr -d \\036)" '2'
assert_eq "$(echo "$output" | jq --seq .addresses[0].address[3] | tr -d \\036)" '1'
# test for listing multiple machines.
long_running_machine_start
varlinkctl --more call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{}'
varlinkctl --more call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{"acquireMetadata": "no"}'
varlinkctl --more call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{"acquireMetadata": "graceful"}'
# check if machined does not try to send anything after error message
journalctl --sync
TS="$(date '+%H:%M:%S')"
(! varlinkctl --more call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{"acquireMetadata": "yes"}')
journalctl --sync
(! journalctl -u systemd-machined.service --since="$TS" --grep 'Connection busy')
# terminate machines
machinectl terminate "container-without-os-release"
machinectl terminate "long-running"
# wait for the container being stopped, otherwise acquiring image metadata by io.systemd.MachineImage.List may fail in the below.
timeout 30 bash -c 'until [[ "$(systemctl is-active systemd-nspawn@long-running.service)" == "inactive" ]]; do sleep .5; done'
(ip addr show lo | grep -q 192.168.1.100) || ip address add 192.168.1.100/24 dev lo
(! varlinkctl --more call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{"name": ".host"}' | grep 'addresses')