1
0
mirror of https://github.com/systemd/systemd synced 2026-04-06 15:14:49 +02:00

Compare commits

..

12 Commits

Author SHA1 Message Date
Frantisek Sumsal
6a05abb9b4 test: don't register short-living containers with machined
As registering the container creates a scope which might not be cleaned
up completely before we run a next command in the same container,
causing intermittent test fails:

[   63.424739] TEST-13-NSPAWN.sh[4231]: + systemd-nspawn --directory=/var/lib/machines/TEST-13-NSPAWN.sanity.zH2 bash -xec '[[ $USER == root ]]'
[   63.427504] systemd-nspawn[4381]: ░ Spawning container TEST-13-NSPAWN.sanity.zH2 on /var/lib/machines/TEST-13-NSPAWN.sanity.zH2.
[   63.437154] systemd[1]: Started TEST-13-NSPAWN.sanity.zH2.scope - Container TEST-13-NSPAWN.sanity.zH2.
[   63.437765] systemd-machined[1164]: New machine TEST-13-NSPAWN.sanity.zH2.
[   63.440311] TEST-13-NSPAWN.sh[4381]: + [[ root == root ]]
[   63.442046] systemd[1]: TEST-13-NSPAWN.sanity.zH2.scope: Killed unit cgroup '/machine.slice/TEST-13-NSPAWN.sanity.zH2.scope' with SIGKILL on client request.
[   63.442583] systemd-nspawn[4381]: Container TEST-13-NSPAWN.sanity.zH2 exited successfully.
[   63.443073] systemd-machined[1164]: Machine TEST-13-NSPAWN.sanity.zH2 terminated.
[   63.448728] TEST-13-NSPAWN.sh[4231]: + systemd-nspawn --directory=/var/lib/machines/TEST-13-NSPAWN.sanity.zH2 --user=testuser bash -xec '[[ $USER == testuser ]]'
[   63.451209] systemd-nspawn[4385]: ░ Spawning container TEST-13-NSPAWN.sanity.zH2 on /var/lib/machines/TEST-13-NSPAWN.sanity.zH2.
[   63.455295] systemd-nspawn[4385]: Failed to allocate scope: Unit TEST-13-NSPAWN.sanity.zH2.scope was already loaded or has a fragment file.
[   63.456139] systemd[1]: TEST-13-NSPAWN.sanity.zH2.scope: Deactivated successfully.
[   63.461292] TEST-13-NSPAWN.sh[2839]: + at_exit

Since even systemd-nspawn's man page suggests not to register containers
with systemd-machined if they don't run a service manager, let's do just
that to mitigate the race.

Resolves: #39629
2025-11-10 18:30:55 +00:00
Gero Schwäricke
032ea7ca12 rules: add rule to generate unique symlinks for gpio devices
Regular generated paths make it hard to identify individual GPIO
devices. This is a challenge when using multiple USB-to-GPIO adapters
like Diolan DLN2.

The unique symlinks from this rule can be used, e.g., with gpiod tools.
2025-11-10 23:22:08 +09:00
Yu Watanabe
9485379850
resolve: several follow-ups for json output (#39605)
Follow-ups for #38960.
2025-11-10 22:32:28 +09:00
Yu Watanabe
ecf3c8702d test-ndisc-rs: drop unused verbose flag and log in the debug level 2025-11-10 20:49:21 +09:00
Yu Watanabe
1d17b23dd6 test: avoid service name collision
The same service name was accidentally used for two invocations:
```
[ 1801.197993] H TEST-04-JOURNAL.sh[20563]: + assert_rc 0 journalctl -q -D /run/log/journal/e30adae55e664d328af442bf5df694c8/ -u test-23833.service --grep service=test-23833.service
[ 1801.198527] H TEST-04-JOURNAL.sh[20685]: + set +ex
[ 1801.222676] H TEST-04-JOURNAL.sh[20686]: Nov 10 03:18:51 H systemd[1]: test-23833.service: About to execute: /usr/bin/bash -c "echo service=test-23833.service invocation=\$INVOCATION_ID; journalctl --sync"
[ 1801.222676] H TEST-04-JOURNAL.sh[20686]: Nov 10 03:18:51 H systemd[1]: Started test-23833.service - [systemd-run] /usr/bin/bash -c "echo service=test-23833.service invocation=\$INVOCATION_ID; journalctl --sync".
[ 1801.222676] H TEST-04-JOURNAL.sh[20686]: Nov 10 03:18:51 H (bash)[20681]: test-23833.service: Executing: /usr/bin/bash -c "echo service=test-23833.service invocation=\$INVOCATION_ID; journalctl --sync"
[ 1801.222676] H TEST-04-JOURNAL.sh[20686]: Nov 10 03:18:51 H bash[20681]: service=test-23833.service invocation=1866f15e95924a688dcecde72bf345f6
[ 1801.227878] H TEST-04-JOURNAL.sh[20563]: + assert_rc 1 journalctl -q -D /var/log/journal/e30adae55e664d328af442bf5df694c8/ -u test-23833.service --grep service=test-23833.service
[ 1801.228265] H TEST-04-JOURNAL.sh[20689]: + set +ex
[ 1801.253412] H TEST-04-JOURNAL.sh[20690]: Nov 10 03:18:49 H systemd[1]: test-23833.service: About to execute: /usr/bin/bash -c "echo service=test-23833.service invocation=\$INVOCATION_ID; journalctl --sync"
[ 1801.253412] H TEST-04-JOURNAL.sh[20690]: Nov 10 03:18:49 H systemd[1]: Started test-23833.service - [systemd-run] /usr/bin/bash -c "echo service=test-23833.service invocation=\$INVOCATION_ID; journalctl --sync".
[ 1801.253412] H TEST-04-JOURNAL.sh[20690]: Nov 10 03:18:49 H (bash)[20581]: test-23833.service: Executing: /usr/bin/bash -c "echo service=test-23833.service invocation=\$INVOCATION_ID; journalctl --sync"
[ 1801.253412] H TEST-04-JOURNAL.sh[20690]: Nov 10 03:18:49 H bash[20581]: service=test-23833.service invocation=a3089a62b5624d21bac0a75a3995d8b5
[ 1801.258158] H TEST-04-JOURNAL.sh[20692]: FAIL: expected: '1' actual: '0'
```
2025-11-10 20:49:00 +09:00
Yu Watanabe
b1a95a3aa7 resolvectl: drop an empty line between function call and error handling
Follow-up for 0536b37629c163af268975fcc3017cad823b1e9b.
2025-11-10 11:02:51 +09:00
Yu Watanabe
f2f89678ec resolvectl: use string table
Follow-up for 0536b37629c163af268975fcc3017cad823b1e9b.
2025-11-10 11:02:51 +09:00
Yu Watanabe
fa05718dea resolvectl: rename STATUS_PRIVATE -> STATUS_DNS_OVER_TLS 2025-11-10 11:02:51 +09:00
Yu Watanabe
6f841e58b1 resolve: do not dump cache entries when not necessary
Follow-up for 306375c36804c5c85cd9b77b353f40edf116521d.
2025-11-10 11:02:51 +09:00
Yu Watanabe
76c674ec25 resolve: use enum for several fields
Unfortunately, we have already exposed dnssec with hyphen, so we cannot
change it as enum.
2025-11-10 11:02:33 +09:00
Yu Watanabe
c6b6ac63ea resolve: drop unnecessary preparation of empty arrays 2025-11-10 11:01:39 +09:00
Yu Watanabe
a37239d05f resolve: use JSON_BUILD_PAIR_TRISTATE_NON_NULL for default_route 2025-11-10 11:01:38 +09:00
14 changed files with 219 additions and 167 deletions

17
rules.d/60-gpiochip.rules Normal file
View File

@ -0,0 +1,17 @@
# do not edit this file, it will be overwritten on update
ACTION=="remove", GOTO="gpiochip_end"
SUBSYSTEM!="gpio", GOTO="gpiochip_end"
KERNEL!="gpiochip[0-9]*", GOTO="gpiochip_end"
IMPORT{builtin}="path_id"
ENV{ID_PATH_WITH_USB_REVISION}=="?*", SYMLINK+="gpio/by-path/$env{ID_PATH_WITH_USB_REVISION}"
SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
ENV{ID_BUS}=="", GOTO="gpiochip_end"
ENV{ID_SERIAL}=="", GOTO="gpiochip_end"
ENV{ID_USB_INTERFACE_NUM}=="", GOTO="gpiochip_end"
SYMLINK+="gpio/by-id/$env{ID_BUS}-$env{ID_SERIAL}-if$env{ID_USB_INTERFACE_NUM}"
LABEL="gpiochip_end"

View File

@ -12,6 +12,7 @@ rules = [
'60-drm.rules', '60-drm.rules',
'60-evdev.rules', '60-evdev.rules',
'60-fido-id.rules', '60-fido-id.rules',
'60-gpiochip.rules',
'60-infiniband.rules', '60-infiniband.rules',
'60-input-id.rules', '60-input-id.rules',
'60-persistent-alsa.rules', '60-persistent-alsa.rules',

View File

@ -22,8 +22,6 @@ static struct ether_addr mac_addr = {
.ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
}; };
static bool verbose = false;
static void router_dump(sd_ndisc_router *rt) { static void router_dump(sd_ndisc_router *rt) {
struct in6_addr addr; struct in6_addr addr;
uint8_t hop_limit; uint8_t hop_limit;
@ -188,8 +186,7 @@ static int send_ra(uint8_t flags) {
assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) == assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
sizeof(advertisement)); sizeof(advertisement));
if (verbose) log_debug("%s: Sent RA with flag 0x%02x", __func__, flags);
printf(" sent RA with flag 0x%02x\n", flags);
return 0; return 0;
} }
@ -219,8 +216,7 @@ static void test_callback_ra(sd_ndisc *nd, sd_ndisc_event_t event, void *message
assert_se(flags == flags_array[idx]); assert_se(flags == flags_array[idx]);
idx++; idx++;
if (verbose) log_debug("%s: Got event 0x%02" PRIx64, __func__, flags);
printf(" got event 0x%02" PRIx64 "\n", flags);
if (idx < ELEMENTSOF(flags_array)) { if (idx < ELEMENTSOF(flags_array)) {
send_ra(flags_array[idx]); send_ra(flags_array[idx]);
@ -309,13 +305,10 @@ static int send_ra_invalid_domain(uint8_t flags) {
advertisement[5] = flags; advertisement[5] = flags;
printf("sizeof(nd_router_advert)=%zu\n", sizeof(struct nd_router_advert));
assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) == assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
sizeof(advertisement)); sizeof(advertisement));
if (verbose) log_debug("%s: Sent RA with flag 0x%02x", __func__, flags);
printf(" sent RA with flag 0x%02x\n", flags);
return 0; return 0;
} }
@ -391,8 +384,8 @@ static int send_na(uint32_t flags) {
((struct nd_neighbor_advert*) advertisement)->nd_na_flags_reserved = flags; ((struct nd_neighbor_advert*) advertisement)->nd_na_flags_reserved = flags;
assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) == sizeof(advertisement)); assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) == sizeof(advertisement));
if (verbose)
printf(" sent NA with flag 0x%02x\n", flags); log_debug("%s: Sent NA with flag 0x%02x", __func__, flags);
return 0; return 0;
} }
@ -422,8 +415,7 @@ static void test_callback_na(sd_ndisc *nd, sd_ndisc_event_t event, void *message
assert_se(flags == flags_array[idx]); assert_se(flags == flags_array[idx]);
idx++; idx++;
if (verbose) log_debug("%s: Got event 0x%02" PRIx32, __func__, flags);
printf(" got event 0x%02" PRIx32 "\n", flags);
if (idx < ELEMENTSOF(flags_array)) { if (idx < ELEMENTSOF(flags_array)) {
send_na(flags_array[idx]); send_na(flags_array[idx]);

View File

@ -102,11 +102,27 @@ typedef enum StatusMode {
STATUS_DEFAULT_ROUTE, STATUS_DEFAULT_ROUTE,
STATUS_LLMNR, STATUS_LLMNR,
STATUS_MDNS, STATUS_MDNS,
STATUS_PRIVATE, STATUS_DNS_OVER_TLS,
STATUS_DNSSEC, STATUS_DNSSEC,
STATUS_NTA, STATUS_NTA,
_STATUS_MAX,
_STATUS_INVALID = -EINVAL,
} StatusMode; } StatusMode;
static const char* const status_mode_json_field_table[_STATUS_MAX] = {
[STATUS_ALL] = NULL,
[STATUS_DNS] = "servers",
[STATUS_DOMAIN] = "searchDomains",
[STATUS_DEFAULT_ROUTE] = "defaultRoute",
[STATUS_LLMNR] = "llmnr",
[STATUS_MDNS] = "mDNS",
[STATUS_DNS_OVER_TLS] = "dnsOverTLS",
[STATUS_DNSSEC] = "dnssec",
[STATUS_NTA] = "negativeTrustAnchors",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(status_mode_json_field, StatusMode);
typedef struct InterfaceInfo { typedef struct InterfaceInfo {
int index; int index;
const char *name; const char *name;
@ -1793,41 +1809,6 @@ static char** global_protocol_status(const GlobalInfo *info) {
return TAKE_PTR(s); return TAKE_PTR(s);
} }
static const char* status_mode_to_json_field(StatusMode mode) {
switch (mode) {
case STATUS_ALL:
return NULL;
case STATUS_DNS:
return "servers";
case STATUS_DOMAIN:
return "searchDomains";
case STATUS_DEFAULT_ROUTE:
return "defaultRoute";
case STATUS_LLMNR:
return "llmnr";
case STATUS_MDNS:
return "mDNS";
case STATUS_PRIVATE:
return "dnsOverTLS";
case STATUS_DNSSEC:
return "dnssec";
case STATUS_NTA:
return "negativeTrustAnchors";
default:
assert_not_reached();
}
}
static int status_json_filter_fields(sd_json_variant **configuration, StatusMode mode) { static int status_json_filter_fields(sd_json_variant **configuration, StatusMode mode) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
sd_json_variant *w; sd_json_variant *w;
@ -1836,7 +1817,7 @@ static int status_json_filter_fields(sd_json_variant **configuration, StatusMode
assert(configuration); assert(configuration);
field = status_mode_to_json_field(mode); field = status_mode_json_field_to_string(mode);
if (!field) if (!field)
/* Nothing to filter for this mode. */ /* Nothing to filter for this mode. */
return 0; return 0;
@ -1869,7 +1850,6 @@ static int status_json_filter_links(sd_json_variant **configuration, char **link
if (links) if (links)
STRV_FOREACH(ifname, links) { STRV_FOREACH(ifname, links) {
int ifindex = rtnl_resolve_interface_or_warn(/* rtnl= */ NULL, *ifname); int ifindex = rtnl_resolve_interface_or_warn(/* rtnl= */ NULL, *ifname);
if (ifindex < 0) if (ifindex < 0)
return ifindex; return ifindex;
@ -2037,7 +2017,7 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode
return 0; return 0;
case STATUS_PRIVATE: case STATUS_DNS_OVER_TLS:
printf("%sLink %i (%s)%s: %s\n", printf("%sLink %i (%s)%s: %s\n",
ansi_highlight(), ifindex, name, ansi_normal(), ansi_highlight(), ifindex, name, ansi_normal(),
strna(link_info.dns_over_tls)); strna(link_info.dns_over_tls));
@ -2265,7 +2245,7 @@ static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
return 0; return 0;
case STATUS_PRIVATE: case STATUS_DNS_OVER_TLS:
printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(), printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
strna(global_info.dns_over_tls)); strna(global_info.dns_over_tls));
@ -3010,10 +2990,10 @@ static int verb_dns_over_tls(int argc, char **argv, void *userdata) {
} }
if (arg_ifindex <= 0) if (arg_ifindex <= 0)
return status_all(bus, STATUS_PRIVATE); return status_all(bus, STATUS_DNS_OVER_TLS);
if (argc < 3) if (argc < 3)
return status_ifindex(bus, arg_ifindex, NULL, STATUS_PRIVATE, NULL); return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNS_OVER_TLS, NULL);
(void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password); (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);

View File

@ -1793,16 +1793,18 @@ bool dns_scope_is_default_route(DnsScope *scope) {
return true; return true;
} }
int dns_scope_dump_cache_to_json(DnsScope *scope, sd_json_variant **ret) { int dns_scope_to_json(DnsScope *scope, bool with_cache, sd_json_variant **ret) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *cache = NULL; _cleanup_(sd_json_variant_unrefp) sd_json_variant *cache = NULL;
int r; int r;
assert(scope); assert(scope);
assert(ret); assert(ret);
if (with_cache) {
r = dns_cache_dump_to_json(&scope->cache, &cache); r = dns_cache_dump_to_json(&scope->cache, &cache);
if (r < 0) if (r < 0)
return r; return r;
}
return sd_json_buildo( return sd_json_buildo(
ret, ret,
@ -1810,7 +1812,7 @@ int dns_scope_dump_cache_to_json(DnsScope *scope, sd_json_variant **ret) {
SD_JSON_BUILD_PAIR_CONDITION(scope->family != AF_UNSPEC, "family", SD_JSON_BUILD_INTEGER(scope->family)), SD_JSON_BUILD_PAIR_CONDITION(scope->family != AF_UNSPEC, "family", SD_JSON_BUILD_INTEGER(scope->family)),
SD_JSON_BUILD_PAIR_CONDITION(!!scope->link, "ifindex", SD_JSON_BUILD_INTEGER(dns_scope_ifindex(scope))), SD_JSON_BUILD_PAIR_CONDITION(!!scope->link, "ifindex", SD_JSON_BUILD_INTEGER(dns_scope_ifindex(scope))),
SD_JSON_BUILD_PAIR_CONDITION(!!scope->link, "ifname", SD_JSON_BUILD_STRING(dns_scope_ifname(scope))), SD_JSON_BUILD_PAIR_CONDITION(!!scope->link, "ifname", SD_JSON_BUILD_STRING(dns_scope_ifname(scope))),
SD_JSON_BUILD_PAIR_VARIANT("cache", cache), SD_JSON_BUILD_PAIR_CONDITION(with_cache, "cache", SD_JSON_BUILD_VARIANT(cache)),
SD_JSON_BUILD_PAIR_CONDITION(scope->protocol == DNS_PROTOCOL_DNS, SD_JSON_BUILD_PAIR_CONDITION(scope->protocol == DNS_PROTOCOL_DNS,
"dnssec", "dnssec",
SD_JSON_BUILD_STRING(dnssec_mode_to_string(scope->dnssec_mode))), SD_JSON_BUILD_STRING(dnssec_mode_to_string(scope->dnssec_mode))),

View File

@ -120,7 +120,7 @@ int dns_scope_remove_dnssd_registered_services(DnsScope *scope);
bool dns_scope_is_default_route(DnsScope *scope); bool dns_scope_is_default_route(DnsScope *scope);
int dns_scope_dump_cache_to_json(DnsScope *scope, sd_json_variant **ret); int dns_scope_to_json(DnsScope *scope, bool with_cache, sd_json_variant **ret);
int dns_type_suitable_for_protocol(uint16_t type, DnsProtocol protocol); int dns_type_suitable_for_protocol(uint16_t type, DnsProtocol protocol);
int dns_question_types_suitable_for_protocol(DnsQuestion *q, DnsProtocol protocol); int dns_question_types_suitable_for_protocol(DnsQuestion *q, DnsProtocol protocol);

View File

@ -2068,39 +2068,10 @@ static int dns_configuration_json_append(
assert(configuration); assert(configuration);
if (dns_servers) {
r = sd_json_variant_new_array(&dns_servers_json, NULL, 0);
if (r < 0)
return r;
}
if (search_domains) {
r = sd_json_variant_new_array(&search_domains_json, NULL, 0);
if (r < 0)
return r;
}
if (current_dns_server) {
r = dns_server_dump_configuration_to_json(current_dns_server, &current_dns_server_json);
if (r < 0)
return r;
}
if (fallback_dns_servers) {
r = sd_json_variant_new_array(&fallback_dns_servers_json, NULL, 0);
if (r < 0)
return r;
}
SET_FOREACH(scope, dns_scopes) { SET_FOREACH(scope, dns_scopes) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
r = dns_scope_dump_cache_to_json(scope, &v); r = dns_scope_to_json(scope, /* with_cache= */ false, &v);
if (r < 0)
return r;
/* The cache is not relevant to the configuration of the scope. */
r = sd_json_variant_filter(&v, STRV_MAKE("cache"));
if (r < 0) if (r < 0)
return r; return r;
@ -2112,8 +2083,6 @@ static int dns_configuration_json_append(
LIST_FOREACH(servers, s, dns_servers) { LIST_FOREACH(servers, s, dns_servers) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
assert(dns_servers_json);
r = dns_server_dump_configuration_to_json(s, &v); r = dns_server_dump_configuration_to_json(s, &v);
if (r < 0) if (r < 0)
return r; return r;
@ -2126,8 +2095,6 @@ static int dns_configuration_json_append(
LIST_FOREACH(domains, d, search_domains) { LIST_FOREACH(domains, d, search_domains) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
assert(search_domains_json);
r = dns_search_domain_dump_to_json(d, &v); r = dns_search_domain_dump_to_json(d, &v);
if (r < 0) if (r < 0)
return r; return r;
@ -2140,8 +2107,6 @@ static int dns_configuration_json_append(
LIST_FOREACH(servers, s, fallback_dns_servers) { LIST_FOREACH(servers, s, fallback_dns_servers) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
assert(fallback_dns_servers_json);
r = dns_server_dump_configuration_to_json(s, &v); r = dns_server_dump_configuration_to_json(s, &v);
if (r < 0) if (r < 0)
return r; return r;
@ -2156,9 +2121,7 @@ static int dns_configuration_json_append(
JSON_BUILD_PAIR_STRING_NON_EMPTY("ifname", ifname), JSON_BUILD_PAIR_STRING_NON_EMPTY("ifname", ifname),
SD_JSON_BUILD_PAIR_CONDITION(ifindex > 0, "ifindex", SD_JSON_BUILD_UNSIGNED(ifindex)), SD_JSON_BUILD_PAIR_CONDITION(ifindex > 0, "ifindex", SD_JSON_BUILD_UNSIGNED(ifindex)),
JSON_BUILD_PAIR_STRING_NON_EMPTY("delegate", delegate), JSON_BUILD_PAIR_STRING_NON_EMPTY("delegate", delegate),
JSON_BUILD_PAIR_CONDITION_BOOLEAN(ifindex > 0 || !!delegate, JSON_BUILD_PAIR_TRISTATE_NON_NULL("defaultRoute", default_route),
"defaultRoute",
default_route > 0),
JSON_BUILD_PAIR_VARIANT_NON_NULL("currentServer", current_dns_server_json), JSON_BUILD_PAIR_VARIANT_NON_NULL("currentServer", current_dns_server_json),
JSON_BUILD_PAIR_VARIANT_NON_NULL("servers", dns_servers_json), JSON_BUILD_PAIR_VARIANT_NON_NULL("servers", dns_servers_json),
JSON_BUILD_PAIR_VARIANT_NON_NULL("fallbackServers", fallback_dns_servers_json), JSON_BUILD_PAIR_VARIANT_NON_NULL("fallbackServers", fallback_dns_servers_json),
@ -2189,7 +2152,7 @@ static int global_dns_configuration_json_append(Manager *m, sd_json_variant **co
/* ifname = */ NULL, /* ifname = */ NULL,
/* ifindex = */ 0, /* ifindex = */ 0,
/* delegate = */ NULL, /* delegate = */ NULL,
/* default_route = */ 0, /* default_route = */ -1,
manager_get_dns_server(m), manager_get_dns_server(m),
m->dns_servers, m->dns_servers,
m->fallback_dns_servers, m->fallback_dns_servers,
@ -2275,7 +2238,7 @@ static int delegate_dns_configuration_json_append(DnsDelegate *d, sd_json_varian
/* ifname = */ NULL, /* ifname = */ NULL,
/* ifindex = */ 0, /* ifindex = */ 0,
d->id, d->id,
d->default_route, d->default_route > 0, /* Defaults to false. See dns_scope_is_default_route(). */
dns_delegate_get_dns_server(d), dns_delegate_get_dns_server(d),
d->dns_servers, d->dns_servers,
/* fallback_dns_servers = */ NULL, /* fallback_dns_servers = */ NULL,

View File

@ -1270,7 +1270,7 @@ static int vl_method_dump_cache(sd_varlink *link, sd_json_variant *parameters, s
LIST_FOREACH(scopes, s, m->dns_scopes) { LIST_FOREACH(scopes, s, m->dns_scopes) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *j = NULL; _cleanup_(sd_json_variant_unrefp) sd_json_variant *j = NULL;
r = dns_scope_dump_cache_to_json(s, &j); r = dns_scope_to_json(s, /* with_cache= */ true, &j);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -5,6 +5,10 @@
/* We want to reuse several structures from the io.systemd.Resolve interface, namely: /* We want to reuse several structures from the io.systemd.Resolve interface, namely:
* *
* - DNSProtocol
* - DNSOverTLSMode
* - ResolveSupport
* - ResolvConfMode
* - ResourceKey * - ResourceKey
* - ResourceRecord * - ResourceRecord
* - DNSServer * - DNSServer
@ -52,13 +56,13 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
static SD_VARLINK_DEFINE_STRUCT_TYPE( static SD_VARLINK_DEFINE_STRUCT_TYPE(
ScopeCache, ScopeCache,
SD_VARLINK_DEFINE_FIELD(protocol, SD_VARLINK_STRING, 0), SD_VARLINK_DEFINE_FIELD_BY_TYPE(protocol, DNSProtocol, 0),
SD_VARLINK_DEFINE_FIELD(family, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_FIELD(family, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(ifname, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_FIELD(ifname, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(cache, CacheEntry, SD_VARLINK_ARRAY), SD_VARLINK_DEFINE_FIELD_BY_TYPE(cache, CacheEntry, SD_VARLINK_ARRAY),
SD_VARLINK_DEFINE_FIELD(dnssec, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_FIELD(dnssec, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(dnsOverTLS, SD_VARLINK_STRING, SD_VARLINK_NULLABLE)); SD_VARLINK_DEFINE_FIELD_BY_TYPE(dnsOverTLS, DNSOverTLSMode, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD( static SD_VARLINK_DEFINE_METHOD(
DumpCache, DumpCache,
@ -137,6 +141,10 @@ SD_VARLINK_DEFINE_INTERFACE(
&vl_method_DumpServerState, &vl_method_DumpServerState,
&vl_method_DumpStatistics, &vl_method_DumpStatistics,
&vl_method_ResetStatistics, &vl_method_ResetStatistics,
&vl_type_DNSProtocol,
&vl_type_DNSOverTLSMode,
&vl_type_ResolveSupport,
&vl_type_ResolvConfMode,
&vl_type_ResourceKey, &vl_type_ResourceKey,
&vl_type_ResourceRecord, &vl_type_ResourceRecord,
&vl_type_ResourceRecordArray, &vl_type_ResourceRecordArray,

View File

@ -1,7 +1,48 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "resolve-util.h"
#include "varlink-io.systemd.Resolve.h" #include "varlink-io.systemd.Resolve.h"
SD_VARLINK_DEFINE_ENUM_TYPE(
DNSProtocol,
SD_VARLINK_FIELD_COMMENT("DNS"),
SD_VARLINK_DEFINE_ENUM_VALUE(dns),
SD_VARLINK_FIELD_COMMENT("Multicast DNS"),
SD_VARLINK_DEFINE_ENUM_VALUE(mdns),
SD_VARLINK_FIELD_COMMENT("LLMNR"),
SD_VARLINK_DEFINE_ENUM_VALUE(llmnr));
SD_VARLINK_DEFINE_ENUM_TYPE(
DNSOverTLSMode,
SD_VARLINK_FIELD_COMMENT("DNSOverTLS is disabled."),
SD_VARLINK_DEFINE_ENUM_VALUE(no),
SD_VARLINK_FIELD_COMMENT("DNSOverTLS is enabled."),
SD_VARLINK_DEFINE_ENUM_VALUE(yes),
SD_VARLINK_FIELD_COMMENT("Try to use DNSOverTLS, but disabled when the server does not support it."),
SD_VARLINK_DEFINE_ENUM_VALUE(opportunistic));
SD_VARLINK_DEFINE_ENUM_TYPE(
ResolveSupport,
SD_VARLINK_FIELD_COMMENT("The protocol is disabled."),
SD_VARLINK_DEFINE_ENUM_VALUE(no),
SD_VARLINK_FIELD_COMMENT("The protocol is enabled."),
SD_VARLINK_DEFINE_ENUM_VALUE(yes),
SD_VARLINK_FIELD_COMMENT("The protocol is used only for resolving."),
SD_VARLINK_DEFINE_ENUM_VALUE(resolve));
SD_VARLINK_DEFINE_ENUM_TYPE(
ResolvConfMode,
SD_VARLINK_FIELD_COMMENT("/etc/resolv.conf is a symbolic link to "PRIVATE_UPLINK_RESOLV_CONF"."),
SD_VARLINK_DEFINE_ENUM_VALUE(uplink),
SD_VARLINK_FIELD_COMMENT("/etc/resolv.conf is a symbolic link to "PRIVATE_STUB_RESOLV_CONF"."),
SD_VARLINK_DEFINE_ENUM_VALUE(stub),
SD_VARLINK_FIELD_COMMENT("/etc/resolv.conf is a symbolic link to "PRIVATE_STATIC_RESOLV_CONF"."),
SD_VARLINK_DEFINE_ENUM_VALUE(static),
SD_VARLINK_FIELD_COMMENT("/etc/resolv.conf does not exist."),
SD_VARLINK_DEFINE_ENUM_VALUE(missing),
SD_VARLINK_FIELD_COMMENT("/etc/resolv.conf is not managed by systemd-resolved."),
SD_VARLINK_DEFINE_ENUM_VALUE(foreign));
SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_DEFINE_STRUCT_TYPE(
ResourceKey, ResourceKey,
SD_VARLINK_FIELD_COMMENT("The RR class, almost always IN, i.e 0x01. If unspecified defaults to IN."), SD_VARLINK_FIELD_COMMENT("The RR class, almost always IN, i.e 0x01. If unspecified defaults to IN."),
@ -199,7 +240,7 @@ SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_DEFINE_STRUCT_TYPE(
DNSScope, DNSScope,
SD_VARLINK_FIELD_COMMENT("Protocol associated with this scope."), SD_VARLINK_FIELD_COMMENT("Protocol associated with this scope."),
SD_VARLINK_DEFINE_FIELD(protocol, SD_VARLINK_STRING, 0), SD_VARLINK_DEFINE_FIELD_BY_TYPE(protocol, DNSProtocol, 0),
SD_VARLINK_FIELD_COMMENT("Address family associated with this scope."), SD_VARLINK_FIELD_COMMENT("Address family associated with this scope."),
SD_VARLINK_DEFINE_FIELD(family, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_FIELD(family, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Interface index associated with this scope."), SD_VARLINK_FIELD_COMMENT("Interface index associated with this scope."),
@ -209,7 +250,7 @@ SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_FIELD_COMMENT("DNSSEC mode associated with this scope."), SD_VARLINK_FIELD_COMMENT("DNSSEC mode associated with this scope."),
SD_VARLINK_DEFINE_FIELD(dnssec, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_FIELD(dnssec, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNSOverTLS mode associated with this scope."), SD_VARLINK_FIELD_COMMENT("DNSOverTLS mode associated with this scope."),
SD_VARLINK_DEFINE_FIELD(dnsOverTLS, SD_VARLINK_STRING, SD_VARLINK_NULLABLE)); SD_VARLINK_DEFINE_FIELD_BY_TYPE(dnsOverTLS, DNSOverTLSMode, SD_VARLINK_NULLABLE));
SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_DEFINE_STRUCT_TYPE(
DNSConfiguration, DNSConfiguration,
@ -234,13 +275,14 @@ SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_FIELD_COMMENT("DNSSEC mode."), SD_VARLINK_FIELD_COMMENT("DNSSEC mode."),
SD_VARLINK_DEFINE_FIELD(dnssec, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_FIELD(dnssec, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNSOverTLS mode."), SD_VARLINK_FIELD_COMMENT("DNSOverTLS mode."),
SD_VARLINK_DEFINE_FIELD(dnsOverTLS, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_FIELD_BY_TYPE(dnsOverTLS, DNSOverTLSMode, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("LLMNR support."), SD_VARLINK_FIELD_COMMENT("LLMNR support."),
//SD_VARLINK_DEFINE_FIELD_BY_TYPE(llmnr, ResolveSupport, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(llmnr, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_FIELD(llmnr, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("mDNS support."), SD_VARLINK_FIELD_COMMENT("mDNS support."),
SD_VARLINK_DEFINE_FIELD(mDNS, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_FIELD_BY_TYPE(mDNS, ResolveSupport, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("resolv.conf mode, set for global configuration only."), SD_VARLINK_FIELD_COMMENT("resolv.conf mode, set for global configuration only."),
SD_VARLINK_DEFINE_FIELD(resolvConfMode, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_FIELD_BY_TYPE(resolvConfMode, ResolvConfMode, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Array of current DNS scopes."), SD_VARLINK_FIELD_COMMENT("Array of current DNS scopes."),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(scopes, DNSScope, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE)); SD_VARLINK_DEFINE_FIELD_BY_TYPE(scopes, DNSScope, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE));
@ -317,6 +359,14 @@ SD_VARLINK_DEFINE_INTERFACE(
&vl_method_BrowseServices, &vl_method_BrowseServices,
SD_VARLINK_SYMBOL_COMMENT("Current global and per-link DNS configurations."), SD_VARLINK_SYMBOL_COMMENT("Current global and per-link DNS configurations."),
&vl_method_DumpDNSConfiguration, &vl_method_DumpDNSConfiguration,
SD_VARLINK_SYMBOL_COMMENT("The type of protocol."),
&vl_type_DNSProtocol,
SD_VARLINK_SYMBOL_COMMENT("The mode of DNSOverTLS."),
&vl_type_DNSOverTLSMode,
SD_VARLINK_SYMBOL_COMMENT("Whether the protocol is enabled."),
&vl_type_ResolveSupport,
SD_VARLINK_SYMBOL_COMMENT("The management mode of /etc/resolve.conf file."),
&vl_type_ResolvConfMode,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates a resolved address."), SD_VARLINK_SYMBOL_COMMENT("Encapsulates a resolved address."),
&vl_type_ResolvedAddress, &vl_type_ResolvedAddress,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates a resolved host name."), SD_VARLINK_SYMBOL_COMMENT("Encapsulates a resolved host name."),

View File

@ -3,6 +3,10 @@
#include "sd-varlink-idl.h" #include "sd-varlink-idl.h"
extern const sd_varlink_symbol vl_type_DNSProtocol;
extern const sd_varlink_symbol vl_type_DNSOverTLSMode;
extern const sd_varlink_symbol vl_type_ResolveSupport;
extern const sd_varlink_symbol vl_type_ResolvConfMode;
extern const sd_varlink_symbol vl_type_ResourceKey; extern const sd_varlink_symbol vl_type_ResourceKey;
extern const sd_varlink_symbol vl_type_ResourceRecord; extern const sd_varlink_symbol vl_type_ResourceRecord;
extern const sd_varlink_symbol vl_type_DNSServer; extern const sd_varlink_symbol vl_type_DNSServer;

View File

@ -13,6 +13,7 @@
#include "json-util.h" #include "json-util.h"
#include "network-util.h" #include "network-util.h"
#include "pretty-print.h" #include "pretty-print.h"
#include "resolve-util.h"
#include "tests.h" #include "tests.h"
#include "varlink-idl-util.h" #include "varlink-idl-util.h"
#include "varlink-io.systemd.h" #include "varlink-io.systemd.h"
@ -512,13 +513,18 @@ static void test_enum_to_string_name(const char *n, const sd_varlink_symbol *sym
TEST(enums_idl) { TEST(enums_idl) {
TEST_IDL_ENUM(BootEntryType, boot_entry_type, vl_type_BootEntryType); TEST_IDL_ENUM(BootEntryType, boot_entry_type, vl_type_BootEntryType);
TEST_IDL_ENUM_TO_STRING(BootEntrySource, boot_entry_source, vl_type_BootEntrySource); TEST_IDL_ENUM_TO_STRING(BootEntrySource, boot_entry_source, vl_type_BootEntrySource);
TEST_IDL_ENUM(PartitionDesignator, partition_designator, vl_type_PartitionDesignator); TEST_IDL_ENUM(PartitionDesignator, partition_designator, vl_type_PartitionDesignator);
TEST_IDL_ENUM(LinkAddressState, link_address_state, vl_type_LinkAddressState); TEST_IDL_ENUM(LinkAddressState, link_address_state, vl_type_LinkAddressState);
TEST_IDL_ENUM_TO_STRING(LinkAddressState, link_address_state, vl_type_LinkAddressState); TEST_IDL_ENUM_TO_STRING(LinkAddressState, link_address_state, vl_type_LinkAddressState);
TEST_IDL_ENUM(LinkOnlineState, link_online_state, vl_type_LinkOnlineState); TEST_IDL_ENUM(LinkOnlineState, link_online_state, vl_type_LinkOnlineState);
TEST_IDL_ENUM_TO_STRING(LinkOnlineState, link_online_state, vl_type_LinkOnlineState); TEST_IDL_ENUM_TO_STRING(LinkOnlineState, link_online_state, vl_type_LinkOnlineState);
TEST_IDL_ENUM(AddressFamily, link_required_address_family, vl_type_LinkRequiredAddressFamily); TEST_IDL_ENUM(AddressFamily, link_required_address_family, vl_type_LinkRequiredAddressFamily);
TEST_IDL_ENUM_TO_STRING(AddressFamily, link_required_address_family, vl_type_LinkRequiredAddressFamily); TEST_IDL_ENUM_TO_STRING(AddressFamily, link_required_address_family, vl_type_LinkRequiredAddressFamily);
TEST_IDL_ENUM(DnsOverTlsMode, dns_over_tls_mode, vl_type_DNSOverTLSMode);
TEST_IDL_ENUM(ResolveSupport, resolve_support, vl_type_ResolveSupport);
} }
DEFINE_TEST_MAIN(LOG_DEBUG); DEFINE_TEST_MAIN(LOG_DEBUG);

View File

@ -10,8 +10,10 @@ set -o pipefail
MACHINE_ID="$(</etc/machine-id)" MACHINE_ID="$(</etc/machine-id)"
SYSLOG_ID="$(systemd-id128 new)" SYSLOG_ID="$(systemd-id128 new)"
SERVICE_COUNTER=0
write_to_journal() { write_to_journal() {
local service="test-${RANDOM}.service" local service="test-$((SERVICE_COUNTER++))-${RANDOM}.service"
systemd-run -q --wait -u "$service" bash -c "echo service=$service invocation=\$INVOCATION_ID; journalctl --sync" systemd-run -q --wait -u "$service" bash -c "echo service=$service invocation=\$INVOCATION_ID; journalctl --sync"
echo "$service" echo "$service"

View File

@ -90,45 +90,50 @@ testcase_sanity() {
# --template= # --template=
root="$(mktemp -u -d /var/lib/machines/TEST-13-NSPAWN.sanity.XXX)" root="$(mktemp -u -d /var/lib/machines/TEST-13-NSPAWN.sanity.XXX)"
coverage_create_nspawn_dropin "$root" coverage_create_nspawn_dropin "$root"
(! systemd-nspawn --directory="$root" bash -xec 'echo hello') (! systemd-nspawn --register=no --directory="$root" bash -xec 'echo hello')
# Initialize $root from $template (the $root directory must not exist, hence # Initialize $root from $template (the $root directory must not exist, hence
# the `mktemp -u` above) # the `mktemp -u` above)
systemd-nspawn --directory="$root" --template="$template" bash -xec 'echo hello' systemd-nspawn --register=no --directory="$root" --template="$template" bash -xec 'echo hello'
systemd-nspawn --directory="$root" bash -xec 'echo hello; touch /initialized' systemd-nspawn --register=no --directory="$root" bash -xec 'echo hello; touch /initialized'
test -e "$root/initialized" test -e "$root/initialized"
# Check if the $root doesn't get re-initialized once it's not empty # Check if the $root doesn't get re-initialized once it's not empty
systemd-nspawn --directory="$root" --template="$template" bash -xec 'echo hello' systemd-nspawn --register=no --directory="$root" --template="$template" bash -xec 'echo hello'
test -e "$root/initialized" test -e "$root/initialized"
systemd-nspawn --directory="$root" --ephemeral bash -xec 'touch /ephemeral' systemd-nspawn --register=no --directory="$root" --ephemeral bash -xec 'touch /ephemeral'
test ! -e "$root/ephemeral" test ! -e "$root/ephemeral"
(! systemd-nspawn --directory="$root" \ (! systemd-nspawn --register=no \
--directory="$root" \
--read-only \ --read-only \
bash -xec 'touch /nope') bash -xec 'touch /nope')
test ! -e "$root/nope" test ! -e "$root/nope"
systemd-nspawn --image="$image" bash -xec 'echo hello' systemd-nspawn --register=no --image="$image" bash -xec 'echo hello'
# --volatile= # --volatile=
touch "$root/usr/has-usr" touch "$root/usr/has-usr"
# volatile(=yes): rootfs is tmpfs, /usr/ from the OS tree is mounted read only # volatile(=yes): rootfs is tmpfs, /usr/ from the OS tree is mounted read only
systemd-nspawn --directory="$root"\ systemd-nspawn --register=no \
--directory="$root" \
--volatile \ --volatile \
bash -xec 'test -e /usr/has-usr; touch /usr/read-only && exit 1; touch /nope' bash -xec 'test -e /usr/has-usr; touch /usr/read-only && exit 1; touch /nope'
test ! -e "$root/nope" test ! -e "$root/nope"
test ! -e "$root/usr/read-only" test ! -e "$root/usr/read-only"
systemd-nspawn --directory="$root"\ systemd-nspawn --register=no \
--directory="$root" \
--volatile=yes \ --volatile=yes \
bash -xec 'test -e /usr/has-usr; touch /usr/read-only && exit 1; touch /nope' bash -xec 'test -e /usr/has-usr; touch /usr/read-only && exit 1; touch /nope'
test ! -e "$root/nope" test ! -e "$root/nope"
test ! -e "$root/usr/read-only" test ! -e "$root/usr/read-only"
# volatile=state: rootfs is read-only, /var/ is tmpfs # volatile=state: rootfs is read-only, /var/ is tmpfs
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--volatile=state \ --volatile=state \
bash -xec 'test -e /usr/has-usr; mountpoint /var; touch /read-only && exit 1; touch /var/nope' bash -xec 'test -e /usr/has-usr; mountpoint /var; touch /read-only && exit 1; touch /var/nope'
test ! -e "$root/read-only" test ! -e "$root/read-only"
test ! -e "$root/var/nope" test ! -e "$root/var/nope"
# volatile=overlay: tmpfs overlay is mounted over rootfs # volatile=overlay: tmpfs overlay is mounted over rootfs
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--volatile=overlay \ --volatile=overlay \
bash -xec 'test -e /usr/has-usr; touch /nope; touch /var/also-nope; touch /usr/nope-too' bash -xec 'test -e /usr/has-usr; touch /nope; touch /var/also-nope; touch /usr/nope-too'
test ! -e "$root/nope" test ! -e "$root/nope"
@ -138,27 +143,31 @@ testcase_sanity() {
# --volatile= with -U # --volatile= with -U
touch "$root/usr/has-usr" touch "$root/usr/has-usr"
# volatile(=yes): rootfs is tmpfs, /usr/ from the OS tree is mounted read only # volatile(=yes): rootfs is tmpfs, /usr/ from the OS tree is mounted read only
systemd-nspawn --directory="$root"\ systemd-nspawn --register=no \
--directory="$root" \
--volatile \ --volatile \
-U \ -U \
bash -xec 'test -e /usr/has-usr; touch /usr/read-only && exit 1; touch /nope' bash -xec 'test -e /usr/has-usr; touch /usr/read-only && exit 1; touch /nope'
test ! -e "$root/nope" test ! -e "$root/nope"
test ! -e "$root/usr/read-only" test ! -e "$root/usr/read-only"
systemd-nspawn --directory="$root"\ systemd-nspawn --register=no \
--directory="$root" \
--volatile=yes \ --volatile=yes \
-U \ -U \
bash -xec 'test -e /usr/has-usr; touch /usr/read-only && exit 1; touch /nope' bash -xec 'test -e /usr/has-usr; touch /usr/read-only && exit 1; touch /nope'
test ! -e "$root/nope" test ! -e "$root/nope"
test ! -e "$root/usr/read-only" test ! -e "$root/usr/read-only"
# volatile=state: rootfs is read-only, /var/ is tmpfs # volatile=state: rootfs is read-only, /var/ is tmpfs
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--volatile=state \ --volatile=state \
-U \ -U \
bash -xec 'test -e /usr/has-usr; mountpoint /var; touch /read-only && exit 1; touch /var/nope' bash -xec 'test -e /usr/has-usr; mountpoint /var; touch /read-only && exit 1; touch /var/nope'
test ! -e "$root/read-only" test ! -e "$root/read-only"
test ! -e "$root/var/nope" test ! -e "$root/var/nope"
# volatile=overlay: tmpfs overlay is mounted over rootfs # volatile=overlay: tmpfs overlay is mounted over rootfs
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--volatile=overlay \ --volatile=overlay \
-U \ -U \
bash -xec 'test -e /usr/has-usr; touch /nope; touch /var/also-nope; touch /usr/nope-too' bash -xec 'test -e /usr/has-usr; touch /nope; touch /var/also-nope; touch /usr/nope-too'
@ -167,13 +176,16 @@ testcase_sanity() {
test ! -e "$root/usr/nope-too" test ! -e "$root/usr/nope-too"
# --machine=, --hostname= # --machine=, --hostname=
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--machine="foo-bar.baz" \ --machine="foo-bar.baz" \
bash -xec '[[ $(hostname) == foo-bar.baz ]]' bash -xec '[[ $(hostname) == foo-bar.baz ]]'
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--hostname="hello.world.tld" \ --hostname="hello.world.tld" \
bash -xec '[[ $(hostname) == hello.world.tld ]]' bash -xec '[[ $(hostname) == hello.world.tld ]]'
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--machine="foo-bar.baz" \ --machine="foo-bar.baz" \
--hostname="hello.world.tld" \ --hostname="hello.world.tld" \
bash -xec '[[ $(hostname) == hello.world.tld ]]' bash -xec '[[ $(hostname) == hello.world.tld ]]'
@ -181,13 +193,14 @@ testcase_sanity() {
# --uuid= # --uuid=
rm -f "$root/etc/machine-id" rm -f "$root/etc/machine-id"
uuid="deadbeef-dead-dead-beef-000000000000" uuid="deadbeef-dead-dead-beef-000000000000"
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--uuid="$uuid" \ --uuid="$uuid" \
bash -xec "[[ \$container_uuid == $uuid ]]" bash -xec "[[ \$container_uuid == $uuid ]]"
# --as-pid2 # --as-pid2
systemd-nspawn --directory="$root" bash -xec '[[ $$ -eq 1 ]]' systemd-nspawn --register=no --directory="$root" bash -xec '[[ $$ -eq 1 ]]'
systemd-nspawn --directory="$root" --as-pid2 bash -xec '[[ $$ -eq 2 ]]' systemd-nspawn --register=no --directory="$root" --as-pid2 bash -xec '[[ $$ -eq 2 ]]'
# --user= # --user=
# "Fake" getent passwd's bare minimum, so we don't have to pull it in # "Fake" getent passwd's bare minimum, so we don't have to pull it in
@ -208,28 +221,32 @@ EOF
# bash will end up loading libnss_systemd.so which breaks when libnss_systemd.so is built with sanitizers # bash will end up loading libnss_systemd.so which breaks when libnss_systemd.so is built with sanitizers
# as bash isn't invoked with the necessary environment variables for that. # as bash isn't invoked with the necessary environment variables for that.
useradd --root="$root" --uid 1000 --user-group --create-home testuser useradd --root="$root" --uid 1000 --user-group --create-home testuser
systemd-nspawn --directory="$root" bash -xec '[[ $USER == root ]]' systemd-nspawn --register=no --directory="$root" bash -xec '[[ $USER == root ]]'
systemd-nspawn --directory="$root" --user=testuser bash -xec '[[ $USER == testuser ]]' systemd-nspawn --register=no --directory="$root" --user=testuser bash -xec '[[ $USER == testuser ]]'
# --settings= + .nspawn files # --settings= + .nspawn files
mkdir -p /run/systemd/nspawn/ mkdir -p /run/systemd/nspawn/
uuid="deadbeef-dead-dead-beef-000000000000" uuid="deadbeef-dead-dead-beef-000000000000"
echo -ne "[Exec]\nMachineID=deadbeef-dead-dead-beef-111111111111" >/run/systemd/nspawn/foo-bar.nspawn echo -ne "[Exec]\nMachineID=deadbeef-dead-dead-beef-111111111111" >/run/systemd/nspawn/foo-bar.nspawn
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--machine=foo-bar \ --machine=foo-bar \
--settings=yes \ --settings=yes \
bash -xec '[[ $container_uuid == deadbeef-dead-dead-beef-111111111111 ]]' bash -xec '[[ $container_uuid == deadbeef-dead-dead-beef-111111111111 ]]'
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--machine=foo-bar \ --machine=foo-bar \
--uuid="$uuid" \ --uuid="$uuid" \
--settings=yes \ --settings=yes \
bash -xec "[[ \$container_uuid == $uuid ]]" bash -xec "[[ \$container_uuid == $uuid ]]"
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--machine=foo-bar \ --machine=foo-bar \
--uuid="$uuid" \ --uuid="$uuid" \
--settings=override \ --settings=override \
bash -xec '[[ $container_uuid == deadbeef-dead-dead-beef-111111111111 ]]' bash -xec '[[ $container_uuid == deadbeef-dead-dead-beef-111111111111 ]]'
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--machine=foo-bar \ --machine=foo-bar \
--uuid="$uuid" \ --uuid="$uuid" \
--settings=trusted \ --settings=trusted \
@ -240,7 +257,8 @@ EOF
touch "$tmpdir/1/one" "$tmpdir/2/two" "$tmpdir/3/three" touch "$tmpdir/1/one" "$tmpdir/2/two" "$tmpdir/3/three"
touch "$tmpdir/foo" touch "$tmpdir/foo"
# --bind= # --bind=
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
${COVERAGE_BUILD_DIR:+--bind="$COVERAGE_BUILD_DIR"} \ ${COVERAGE_BUILD_DIR:+--bind="$COVERAGE_BUILD_DIR"} \
--bind="$tmpdir:/foo" \ --bind="$tmpdir:/foo" \
--bind="$tmpdir:/also-foo:noidmap,norbind" \ --bind="$tmpdir:/also-foo:noidmap,norbind" \
@ -248,7 +266,8 @@ EOF
# --bind= recursive # --bind= recursive
rm -f "$tmpdir/bar" rm -f "$tmpdir/bar"
mount --bind "$tmpdir/1" "$tmpdir/2" mount --bind "$tmpdir/1" "$tmpdir/2"
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
${COVERAGE_BUILD_DIR:+--bind="$COVERAGE_BUILD_DIR"} \ ${COVERAGE_BUILD_DIR:+--bind="$COVERAGE_BUILD_DIR"} \
--bind="$tmpdir:/foo" \ --bind="$tmpdir:/foo" \
--bind="$tmpdir:/also-foo:noidmap,norbind" \ --bind="$tmpdir:/also-foo:noidmap,norbind" \
@ -256,46 +275,52 @@ EOF
umount "$tmpdir/2" umount "$tmpdir/2"
test -e "$tmpdir/bar" test -e "$tmpdir/bar"
# --bind-ro= # --bind-ro=
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--bind-ro="$tmpdir:/foo" \ --bind-ro="$tmpdir:/foo" \
--bind-ro="$tmpdir:/bar:noidmap,norbind" \ --bind-ro="$tmpdir:/bar:noidmap,norbind" \
bash -xec 'test -e /foo/foo; touch /foo/baz && exit 1; touch /bar && exit 1; true' bash -xec 'test -e /foo/foo; touch /foo/baz && exit 1; touch /bar && exit 1; true'
# --inaccessible= # --inaccessible=
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--inaccessible=/var \ --inaccessible=/var \
bash -xec 'touch /var/foo && exit 1; true' bash -xec 'touch /var/foo && exit 1; true'
# --tmpfs= # --tmpfs=
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--tmpfs=/var:rw,nosuid,noexec \ --tmpfs=/var:rw,nosuid,noexec \
bash -xec 'touch /var/nope' bash -xec 'touch /var/nope'
test ! -e "$root/var/nope" test ! -e "$root/var/nope"
# --overlay= # --overlay=
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--overlay="$tmpdir/1:$tmpdir/2:$tmpdir/3:/var" \ --overlay="$tmpdir/1:$tmpdir/2:$tmpdir/3:/var" \
bash -xec 'test -e /var/one; test -e /var/two; test -e /var/three; touch /var/foo' bash -xec 'test -e /var/one; test -e /var/two; test -e /var/three; touch /var/foo'
test -e "$tmpdir/3/foo" test -e "$tmpdir/3/foo"
# --overlay-ro= # --overlay-ro=
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--overlay-ro="$tmpdir/1:$tmpdir/2:$tmpdir/3:/var" \ --overlay-ro="$tmpdir/1:$tmpdir/2:$tmpdir/3:/var" \
bash -xec 'test -e /var/one; test -e /var/two; test -e /var/three; touch /var/nope && exit 1; true' bash -xec 'test -e /var/one; test -e /var/two; test -e /var/three; touch /var/nope && exit 1; true'
test ! -e "$tmpdir/3/nope" test ! -e "$tmpdir/3/nope"
rm -fr "$tmpdir" rm -fr "$tmpdir"
# --port (sanity only) # --port (sanity only)
systemd-nspawn --network-veth --directory="$root" --port=80 --port=90 true systemd-nspawn --register=no --network-veth --directory="$root" --port=80 --port=90 true
systemd-nspawn --network-veth --directory="$root" --port=80:8080 true systemd-nspawn --register=no --network-veth --directory="$root" --port=80:8080 true
systemd-nspawn --network-veth --directory="$root" --port=tcp:80 true systemd-nspawn --register=no --network-veth --directory="$root" --port=tcp:80 true
systemd-nspawn --network-veth --directory="$root" --port=tcp:80:8080 true systemd-nspawn --register=no --network-veth --directory="$root" --port=tcp:80:8080 true
systemd-nspawn --network-veth --directory="$root" --port=udp:80 true systemd-nspawn --register=no --network-veth --directory="$root" --port=udp:80 true
systemd-nspawn --network-veth --directory="$root" --port=udp:80:8080 --port=tcp:80:8080 true systemd-nspawn --register=no --network-veth --directory="$root" --port=udp:80:8080 --port=tcp:80:8080 true
(! systemd-nspawn --network-veth --directory="$root" --port= true) (! systemd-nspawn --register=no --network-veth --directory="$root" --port= true)
(! systemd-nspawn --network-veth --directory="$root" --port=-1 true) (! systemd-nspawn --register=no --network-veth --directory="$root" --port=-1 true)
(! systemd-nspawn --network-veth --directory="$root" --port=: true) (! systemd-nspawn --register=no --network-veth --directory="$root" --port=: true)
(! systemd-nspawn --network-veth --directory="$root" --port=icmp:80:8080 true) (! systemd-nspawn --register=no --network-veth --directory="$root" --port=icmp:80:8080 true)
(! systemd-nspawn --network-veth --directory="$root" --port=tcp::8080 true) (! systemd-nspawn --register=no --network-veth --directory="$root" --port=tcp::8080 true)
(! systemd-nspawn --network-veth --directory="$root" --port=8080: true) (! systemd-nspawn --register=no --network-veth --directory="$root" --port=8080: true)
# Exercise adding/removing ports from an interface # Exercise adding/removing ports from an interface
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--network-veth \ --network-veth \
--port=6667 \ --port=6667 \
--port=80:8080 \ --port=80:8080 \
@ -305,12 +330,14 @@ EOF
# --load-credential=, --set-credential= # --load-credential=, --set-credential=
echo "foo bar" >/tmp/cred.path echo "foo bar" >/tmp/cred.path
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--load-credential=cred.path:/tmp/cred.path \ --load-credential=cred.path:/tmp/cred.path \
--set-credential="cred.set:hello world" \ --set-credential="cred.set:hello world" \
bash -xec '[[ "$(</run/host/credentials/cred.path)" == "foo bar" ]]; [[ "$(</run/host/credentials/cred.set)" == "hello world" ]]' bash -xec '[[ "$(</run/host/credentials/cred.path)" == "foo bar" ]]; [[ "$(</run/host/credentials/cred.set)" == "hello world" ]]'
# Combine with --user to ensure creds are still readable # Combine with --user to ensure creds are still readable
systemd-nspawn --directory="$root" \ systemd-nspawn --register=no \
--directory="$root" \
--user=testuser \ --user=testuser \
--no-new-privileges=yes \ --no-new-privileges=yes \
--load-credential=cred.path:/tmp/cred.path \ --load-credential=cred.path:/tmp/cred.path \
@ -319,9 +346,9 @@ EOF
rm -f /tmp/cred.path rm -f /tmp/cred.path
# Assorted tests # Assorted tests
systemd-nspawn --directory="$root" --suppress-sync=yes bash -xec 'echo hello' systemd-nspawn --register=no --directory="$root" --suppress-sync=yes bash -xec 'echo hello'
systemd-nspawn --capability=help systemd-nspawn --capability=help
systemd-nspawn --directory="$root" --capability=all bash -xec 'echo hello' systemd-nspawn --register=no --directory="$root" --capability=all bash -xec 'echo hello'
systemd-nspawn --resolv-conf=help systemd-nspawn --resolv-conf=help
systemd-nspawn --timezone=help systemd-nspawn --timezone=help
@ -1311,7 +1338,7 @@ testcase_fuse() {
# "cat: -: Operation not permitted" # pass the test; opened but not read # "cat: -: Operation not permitted" # pass the test; opened but not read
# "bash: line 1: /dev/fuse: Operation not permitted" # fail the test; could not open # "bash: line 1: /dev/fuse: Operation not permitted" # fail the test; could not open
# "" # fail the test; reading worked # "" # fail the test; reading worked
[[ "$(systemd-nspawn --pipe --directory="$root" \ [[ "$(systemd-nspawn --register=no --pipe --directory="$root" \
bash -c 'cat <>/dev/fuse' 2>&1)" == 'cat: -: Operation not permitted' ]] bash -c 'cat <>/dev/fuse' 2>&1)" == 'cat: -: Operation not permitted' ]]
rm -fr "$root" rm -fr "$root"
@ -1351,7 +1378,7 @@ testcase_unpriv_fuse() {
} }
test_tun() { test_tun() {
systemd-nspawn "$@" bash -xec '[[ -c /dev/net/tun ]]; [[ "$(stat /dev/net/tun --format=%u)" == 0 ]]; [[ "$(stat /dev/net/tun --format=%g)" == 0 ]]' systemd-nspawn --register=no "$@" bash -xec '[[ -c /dev/net/tun ]]; [[ "$(stat /dev/net/tun --format=%u)" == 0 ]]; [[ "$(stat /dev/net/tun --format=%g)" == 0 ]]'
# check if the owner of the host device is unchanged, see issue #34243. # check if the owner of the host device is unchanged, see issue #34243.
[[ "$(stat /dev/net/tun --format=%u)" == 0 ]] [[ "$(stat /dev/net/tun --format=%u)" == 0 ]]
@ -1360,7 +1387,7 @@ test_tun() {
# Without DeviceAllow= for /dev/net/tun, see issue #35116. # Without DeviceAllow= for /dev/net/tun, see issue #35116.
systemd-run \ systemd-run \
--wait -p Environment=SYSTEMD_LOG_LEVEL=debug -p DevicePolicy=closed -p DeviceAllow="char-pts rw" \ --wait -p Environment=SYSTEMD_LOG_LEVEL=debug -p DevicePolicy=closed -p DeviceAllow="char-pts rw" \
systemd-nspawn "$@" bash -xec '[[ ! -e /dev/net/tun ]]' systemd-nspawn --register=no "$@" bash -xec '[[ ! -e /dev/net/tun ]]'
[[ "$(stat /dev/net/tun --format=%u)" == 0 ]] [[ "$(stat /dev/net/tun --format=%u)" == 0 ]]
[[ "$(stat /dev/net/tun --format=%g)" == 0 ]] [[ "$(stat /dev/net/tun --format=%g)" == 0 ]]
@ -1440,7 +1467,7 @@ testcase_link_journal_host() {
for i in no yes pick; do for i in no yes pick; do
systemd-nspawn \ systemd-nspawn \
--directory="$root" --private-users="$i" --link-journal=host \ --register=no --directory="$root" --private-users="$i" --link-journal=host \
bash -xec 'p="/var/log/journal/$(cat /etc/machine-id)"; mountpoint "$p"; [[ "$(stat "$p" --format=%u)" == 0 ]]; touch "$p/hoge"' bash -xec 'p="/var/log/journal/$(cat /etc/machine-id)"; mountpoint "$p"; [[ "$(stat "$p" --format=%u)" == 0 ]]; touch "$p/hoge"'
[[ "$(stat "${hoge}/hoge" --format=%u)" == 0 ]] [[ "$(stat "${hoge}/hoge" --format=%u)" == 0 ]]