1
0
mirror of https://github.com/systemd/systemd synced 2025-10-07 20:54:45 +02:00

Compare commits

...

19 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek
6634a39469
Merge pull request #19266 from mrc0mmand/testsuite-shellcheck
test: make the test scripts shellcheck-compliant
2021-04-14 13:58:01 +02:00
Yu Watanabe
c68ede3952 util: shorten allow_listed_char_for_devnode() 2021-04-14 11:04:46 +01:00
Yu Watanabe
a2b1572ce4
Merge pull request #19287 from yuwata/network-manage-foreign-routing-policy-rule-19106
network: add ManageForeignRoutingPolicyRules= boolean setting
2021-04-14 19:01:41 +09:00
Yu Watanabe
c7cbe25d11
Merge pull request #19069 from LetzteInstanz/waiting_for_address_family
systemd-networkd-wait-online: wait for specific address family
2021-04-14 18:57:39 +09:00
LetzteInstanz
70448bb1c1 test-network: test waiting for address family 2021-04-14 09:00:12 +09:00
LetzteInstanz
6dc4531d16 wait-online: wait for address family
This introduce -4 and -6 commandline options.
2021-04-14 09:00:08 +09:00
LetzteInstanz
bbea881312 sd-network: read IPv4/IPv6 address states from state files 2021-04-14 08:51:08 +09:00
LetzteInstanz
8430841b5e network: save IPv4/IPv6 address states into state file
This also introduces RequiredFamilyForOnline= setting to .network file,
and IPv4AddressState/IPv6AddressState DBus properties.
2021-04-14 08:51:02 +09:00
LetzteInstanz
86ae2d69a3 network: move AddressFamily into network-util for the use by wait-online later 2021-04-14 08:30:18 +09:00
Frantisek Sumsal
84031b5d6e test: bunch of assorted tweaks to make shellcheck happy 2021-04-13 19:14:35 +02:00
Frantisek Sumsal
4544002cae test: use arrays to make things a bit cleaner 2021-04-13 13:20:22 +02:00
Frantisek Sumsal
ea539ad297 test: replace the obsolete `` syntax with $() 2021-04-13 12:08:01 +02:00
Frantisek Sumsal
70ad107bdf test: use an explicit no-op for file truncation 2021-04-13 12:08:01 +02:00
Frantisek Sumsal
f794098356 test: tidy up arithmetic expressions 2021-04-13 12:08:01 +02:00
Frantisek Sumsal
3882526798 test: use quotes where necessary
to avoid possible word splitting.
2021-04-13 12:08:01 +02:00
Frantisek Sumsal
084575ff91 test: use set -eux and set -o pipefail everywhere
This should make the scripts more robust.
2021-04-13 12:08:01 +02:00
Yu Watanabe
3fe23a96d6 man: update description for ManageForeignRoutes= 2021-04-13 12:23:59 +09:00
Yu Watanabe
d94dfe7053 network: introduce ManageForeignRoutingPolicyRules= boolean setting in networkd.conf
The commit 0b81225e5791f660506f7db0ab88078cf296b771 makes that networkd
remove all foreign rules except those with "proto kernel".

But, in some situation, people may want to manage routing policy rules
with other tools, e.g. 'ip' command. To support such the situation,
this introduce ManageForeignRoutingPolicyRules= boolean setting.

Closes #19106.
2021-04-13 12:22:42 +09:00
Yu Watanabe
6bfadad9bb network: add missing default setting in networkd.conf 2021-04-13 12:07:09 +09:00
94 changed files with 938 additions and 555 deletions

View File

@ -62,12 +62,24 @@
If <varname>SpeedMeter=no</varname>, the value is ignored. Defaults to 10sec.</para></listitem> If <varname>SpeedMeter=no</varname>, the value is ignored. Defaults to 10sec.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>ManageForeignRoutingPolicyRules=</varname></term>
<listitem><para>A boolean. When true, <command>systemd-networkd</command> will remove rules
that are not configured in .network files (except for rules with protocol
<literal>kernel</literal>). When false, it will not remove any foreign rules, keeping them even
if they are not configured in a .network file. Defaults to yes.
</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>ManageForeignRoutes=</varname></term> <term><varname>ManageForeignRoutes=</varname></term>
<listitem><para>A boolean. When true, <command>systemd-networkd</command> will store any routes <listitem><para>A boolean. When true, <command>systemd-networkd</command> will remove routes
configured by other tools in its memory. When false, <command>systemd-networkd</command> will that are not configured in .network files (except for routes with protocol
not manage the foreign routes, thus they are kept even if <varname>KeepConfiguration=</varname> <literal>kernel</literal>, <literal>dhcp</literal> when <varname>KeepConfiguration=</varname>
is false. Defaults to yes.</para></listitem> is true or <literal>dhcp</literal>, and <literal>static</literal> when
<varname>KeepConfiguration=</varname> is true or <literal>static</literal>). When false, it will
not remove any foreign routes, keeping them even if they are not configured in a .network file.
Defaults to yes.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>

View File

@ -85,6 +85,34 @@
</para></listitem> </para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>-4</option></term>
<term><option>--ipv4</option></term>
<listitem><para>Waiting for an IPv4 address of each network interface to be configured. If this
option is specified with <option>--any</option>, then
<command>systemd-networkd-wait-online</command> exits with success when at least one interface
becomes online and has an IPv4 address. The option is applied only for the operational state
<literal>degraded</literal> or above. If neither <option>--ipv4</option> nor
<option>--ipv6</option> is specified, then the value from
<varname>RequiredFamilyForOnline=</varname> in the corresponding <filename>.network</filename>
file is used if present.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-6</option></term>
<term><option>--ipv6</option></term>
<listitem><para>Waiting for an IPv6 address of each network interface to be configured. If this
option is specified with <option>--any</option>, then
<command>systemd-networkd-wait-online</command> exits with success when at least one interface
becomes online and has an IPv6 address. The option is applied only for the operational state
<literal>degraded</literal> or above. If neither <option>--ipv4</option> nor
<option>--ipv6</option> is specified, then the value from
<varname>RequiredFamilyForOnline=</varname> in the corresponding <filename>.network</filename>
file is used if present.</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>--any</option></term> <term><option>--any</option></term>

View File

@ -229,6 +229,18 @@
if <literal>RequiredForOnline=no</literal>.</para> if <literal>RequiredForOnline=no</literal>.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>RequiredFamilyForOnline=</varname></term>
<listitem>
<para>Specifies an address family. When specified,
<command>systemd-networkd-wait-online</command> waits for at least one routable or link-local
IP address in the family should be configured on the link. Takes one of
<literal>ipv4</literal>, <literal>ipv6</literal>, <literal>both</literal>, or
<literal>any</literal>. Defaults to <literal>any</literal>. Note that this will be used only
when <varname>RequiredForOnline=</varname> is true, or its minimum operational state is
<literal>degraded</literal> or above. Otherwise, it will be ignored.</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>ActivationPolicy=</varname></term> <term><varname>ActivationPolicy=</varname></term>
<listitem> <listitem>

View File

@ -8,15 +8,12 @@
#include "utf8.h" #include "utf8.h"
int allow_listed_char_for_devnode(char c, const char *white) { int allow_listed_char_for_devnode(char c, const char *white) {
return
if ((c >= '0' && c <= '9') || (c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') || (c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') || (c >= 'a' && c <= 'z') ||
strchr("#+-.:=@_", c) != NULL || strchr("#+-.:=@_", c) ||
(white != NULL && strchr(white, c) != NULL)) (white && strchr(white, c));
return 1;
return 0;
} }
int encode_devnode_name(const char *str, char *str_enc, size_t len) { int encode_devnode_name(const char *str, char *str_enc, size_t len) {
@ -31,7 +28,7 @@ int encode_devnode_name(const char *str, char *str_enc, size_t len) {
seqlen = utf8_encoded_valid_unichar(str + i, SIZE_MAX); seqlen = utf8_encoded_valid_unichar(str + i, SIZE_MAX);
if (seqlen > 1) { if (seqlen > 1) {
if (len-j < (size_t)seqlen) if (len-j < (size_t) seqlen)
return -EINVAL; return -EINVAL;
memcpy(&str_enc[j], &str[i], seqlen); memcpy(&str_enc[j], &str[i], seqlen);

View File

@ -56,6 +56,15 @@ static const char* const link_carrier_state_table[_LINK_CARRIER_STATE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(link_carrier_state, LinkCarrierState); DEFINE_STRING_TABLE_LOOKUP(link_carrier_state, LinkCarrierState);
static const char* const link_required_address_family_table[_ADDRESS_FAMILY_MAX] = {
[ADDRESS_FAMILY_NO] = "any",
[ADDRESS_FAMILY_IPV4] = "ipv4",
[ADDRESS_FAMILY_IPV6] = "ipv6",
[ADDRESS_FAMILY_YES] = "both",
};
DEFINE_STRING_TABLE_LOOKUP(link_required_address_family, AddressFamily);
static const char* const link_address_state_table[_LINK_ADDRESS_STATE_MAX] = { static const char* const link_address_state_table[_LINK_ADDRESS_STATE_MAX] = {
[LINK_ADDRESS_STATE_OFF] = "off", [LINK_ADDRESS_STATE_OFF] = "off",
[LINK_ADDRESS_STATE_DEGRADED] = "degraded", [LINK_ADDRESS_STATE_DEGRADED] = "degraded",

View File

@ -11,6 +11,16 @@
bool network_is_online(void); bool network_is_online(void);
typedef enum AddressFamily {
/* This is a bitmask, though it usually doesn't feel that way! */
ADDRESS_FAMILY_NO = 0,
ADDRESS_FAMILY_IPV4 = 1 << 0,
ADDRESS_FAMILY_IPV6 = 1 << 1,
ADDRESS_FAMILY_YES = ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6,
_ADDRESS_FAMILY_MAX,
_ADDRESS_FAMILY_INVALID = -EINVAL,
} AddressFamily;
typedef enum LinkOperationalState { typedef enum LinkOperationalState {
LINK_OPERSTATE_MISSING, LINK_OPERSTATE_MISSING,
LINK_OPERSTATE_OFF, LINK_OPERSTATE_OFF,
@ -50,6 +60,9 @@ LinkOperationalState link_operstate_from_string(const char *s) _pure_;
const char* link_carrier_state_to_string(LinkCarrierState s) _const_; const char* link_carrier_state_to_string(LinkCarrierState s) _const_;
LinkCarrierState link_carrier_state_from_string(const char *s) _pure_; LinkCarrierState link_carrier_state_from_string(const char *s) _pure_;
const char* link_required_address_family_to_string(AddressFamily s) _const_;
AddressFamily link_required_address_family_from_string(const char *s) _pure_;
const char* link_address_state_to_string(LinkAddressState s) _const_; const char* link_address_state_to_string(LinkAddressState s) _const_;
LinkAddressState link_address_state_from_string(const char *s) _pure_; LinkAddressState link_address_state_from_string(const char *s) _pure_;

View File

@ -48,6 +48,14 @@ _public_ int sd_network_get_address_state(char **state) {
return network_get_string("ADDRESS_STATE", state); return network_get_string("ADDRESS_STATE", state);
} }
_public_ int sd_network_get_ipv4_address_state(char **state) {
return network_get_string("IPV4_ADDRESS_STATE", state);
}
_public_ int sd_network_get_ipv6_address_state(char **state) {
return network_get_string("IPV6_ADDRESS_STATE", state);
}
static int network_get_strv(const char *key, char ***ret) { static int network_get_strv(const char *key, char ***ret) {
_cleanup_strv_free_ char **a = NULL; _cleanup_strv_free_ char **a = NULL;
_cleanup_free_ char *s = NULL; _cleanup_free_ char *s = NULL;
@ -160,6 +168,26 @@ _public_ int sd_network_link_get_operational_state(int ifindex, char **state) {
return network_link_get_string(ifindex, "OPER_STATE", state); return network_link_get_string(ifindex, "OPER_STATE", state);
} }
_public_ int sd_network_link_get_required_family_for_online(int ifindex, char **state) {
_cleanup_free_ char *s = NULL;
int r;
assert_return(state, -EINVAL);
r = network_link_get_string(ifindex, "REQUIRED_FAMILY_FOR_ONLINE", &s);
if (r < 0) {
if (r != -ENODATA)
return r;
s = strdup("any");
if (!s)
return -ENOMEM;
}
*state = TAKE_PTR(s);
return 0;
}
_public_ int sd_network_link_get_carrier_state(int ifindex, char **state) { _public_ int sd_network_link_get_carrier_state(int ifindex, char **state) {
return network_link_get_string(ifindex, "CARRIER_STATE", state); return network_link_get_string(ifindex, "CARRIER_STATE", state);
} }
@ -168,6 +196,14 @@ _public_ int sd_network_link_get_address_state(int ifindex, char **state) {
return network_link_get_string(ifindex, "ADDRESS_STATE", state); return network_link_get_string(ifindex, "ADDRESS_STATE", state);
} }
_public_ int sd_network_link_get_ipv4_address_state(int ifindex, char **state) {
return network_link_get_string(ifindex, "IPV4_ADDRESS_STATE", state);
}
_public_ int sd_network_link_get_ipv6_address_state(int ifindex, char **state) {
return network_link_get_string(ifindex, "IPV6_ADDRESS_STATE", state);
}
_public_ int sd_network_link_get_dhcp6_client_iaid_string(int ifindex, char **iaid) { _public_ int sd_network_link_get_dhcp6_client_iaid_string(int ifindex, char **iaid) {
return network_link_get_string(ifindex, "DHCP6_CLIENT_IAID", iaid); return network_link_get_string(ifindex, "DHCP6_CLIENT_IAID", iaid);
} }

View File

@ -20,9 +20,10 @@ struct ConfigPerfItem;
%struct-type %struct-type
%includes %includes
%% %%
Network.SpeedMeter, config_parse_bool, 0, offsetof(Manager, use_speed_meter) Network.SpeedMeter, config_parse_bool, 0, offsetof(Manager, use_speed_meter)
Network.SpeedMeterIntervalSec, config_parse_sec, 0, offsetof(Manager, speed_meter_interval_usec) Network.SpeedMeterIntervalSec, config_parse_sec, 0, offsetof(Manager, speed_meter_interval_usec)
Network.ManageForeignRoutes, config_parse_bool, 0, offsetof(Manager, manage_foreign_routes) Network.ManageForeignRoutingPolicyRules, config_parse_bool, 0, offsetof(Manager, manage_foreign_rules)
Network.RouteTable, config_parse_route_table_names, 0, 0 Network.ManageForeignRoutes, config_parse_bool, 0, offsetof(Manager, manage_foreign_routes)
DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid) Network.RouteTable, config_parse_route_table_names, 0, 0
DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, duid) DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid)
DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, duid)

View File

@ -684,6 +684,8 @@ const sd_bus_vtable link_vtable[] = {
SD_BUS_PROPERTY("OperationalState", "s", property_get_operational_state, offsetof(Link, operstate), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("OperationalState", "s", property_get_operational_state, offsetof(Link, operstate), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("CarrierState", "s", property_get_carrier_state, offsetof(Link, carrier_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("CarrierState", "s", property_get_carrier_state, offsetof(Link, carrier_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("AddressState", "s", property_get_address_state, offsetof(Link, address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("AddressState", "s", property_get_address_state, offsetof(Link, address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IPv4AddressState", "s", property_get_address_state, offsetof(Link, ipv4_address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IPv6AddressState", "s", property_get_address_state, offsetof(Link, ipv6_address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("AdministrativeState", "s", property_get_administrative_state, offsetof(Link, state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("AdministrativeState", "s", property_get_administrative_state, offsetof(Link, state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("BitRates", "(tt)", property_get_bit_rates, 0, 0), SD_BUS_PROPERTY("BitRates", "(tt)", property_get_bit_rates, 0, 0),

View File

@ -4,6 +4,7 @@
#include <linux/if.h> #include <linux/if.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/if_link.h> #include <linux/if_link.h>
#include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
#include "alloc-util.h" #include "alloc-util.h"
@ -163,12 +164,25 @@ static void link_update_master_operstate(Link *link, NetDev *netdev) {
link_update_operstate(master, true); link_update_operstate(master, true);
} }
static LinkAddressState address_state_from_scope(uint8_t scope) {
if (scope < RT_SCOPE_SITE)
/* universally accessible addresses found */
return LINK_ADDRESS_STATE_ROUTABLE;
if (scope < RT_SCOPE_HOST)
/* only link or site local addresses found */
return LINK_ADDRESS_STATE_DEGRADED;
/* no useful addresses found */
return LINK_ADDRESS_STATE_OFF;
}
void link_update_operstate(Link *link, bool also_update_master) { void link_update_operstate(Link *link, bool also_update_master) {
LinkOperationalState operstate; LinkOperationalState operstate;
LinkCarrierState carrier_state; LinkCarrierState carrier_state;
LinkAddressState address_state; LinkAddressState ipv4_address_state, ipv6_address_state, address_state;
_cleanup_strv_free_ char **p = NULL; _cleanup_strv_free_ char **p = NULL;
uint8_t scope = RT_SCOPE_NOWHERE; uint8_t ipv4_scope = RT_SCOPE_NOWHERE, ipv6_scope = RT_SCOPE_NOWHERE, scope;
bool changed = false; bool changed = false;
Address *address; Address *address;
@ -201,8 +215,11 @@ void link_update_operstate(Link *link, bool also_update_master) {
if (!address_is_ready(address)) if (!address_is_ready(address))
continue; continue;
if (address->scope < scope) if (address->family == AF_INET && address->scope < ipv4_scope)
scope = address->scope; ipv4_scope = address->scope;
if (address->family == AF_INET6 && address->scope < ipv6_scope)
ipv6_scope = address->scope;
} }
/* for operstate we also take foreign addresses into account */ /* for operstate we also take foreign addresses into account */
@ -210,19 +227,18 @@ void link_update_operstate(Link *link, bool also_update_master) {
if (!address_is_ready(address)) if (!address_is_ready(address))
continue; continue;
if (address->scope < scope) if (address->family == AF_INET && address->scope < ipv4_scope)
scope = address->scope; ipv4_scope = address->scope;
if (address->family == AF_INET6 && address->scope < ipv6_scope)
ipv6_scope = address->scope;
} }
if (scope < RT_SCOPE_SITE) ipv4_address_state = address_state_from_scope(ipv4_scope);
/* universally accessible addresses found */ ipv6_address_state = address_state_from_scope(ipv6_scope);
address_state = LINK_ADDRESS_STATE_ROUTABLE;
else if (scope < RT_SCOPE_HOST) scope = MIN(ipv4_scope, ipv6_scope);
/* only link or site local addresses found */ address_state = address_state_from_scope(scope);
address_state = LINK_ADDRESS_STATE_DEGRADED;
else
/* no useful addresses found */
address_state = LINK_ADDRESS_STATE_OFF;
/* Mapping of address and carrier state vs operational state /* Mapping of address and carrier state vs operational state
* carrier state * carrier state
@ -256,6 +272,20 @@ void link_update_operstate(Link *link, bool also_update_master) {
log_oom(); log_oom();
} }
if (link->ipv4_address_state != ipv4_address_state) {
link->ipv4_address_state = ipv4_address_state;
changed = true;
if (strv_extend(&p, "IPv4AddressState") < 0)
log_oom();
}
if (link->ipv6_address_state != ipv6_address_state) {
link->ipv6_address_state = ipv6_address_state;
changed = true;
if (strv_extend(&p, "IPv6AddressState") < 0)
log_oom();
}
if (link->operstate != operstate) { if (link->operstate != operstate) {
link->operstate = operstate; link->operstate = operstate;
changed = true; changed = true;

View File

@ -75,6 +75,8 @@ typedef struct Link {
LinkOperationalState operstate; LinkOperationalState operstate;
LinkCarrierState carrier_state; LinkCarrierState carrier_state;
LinkAddressState address_state; LinkAddressState address_state;
LinkAddressState ipv4_address_state;
LinkAddressState ipv6_address_state;
unsigned address_messages; unsigned address_messages;
unsigned address_remove_messages; unsigned address_remove_messages;

View File

@ -235,6 +235,8 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_PROPERTY("OperationalState", "s", property_get_operational_state, offsetof(Manager, operational_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("OperationalState", "s", property_get_operational_state, offsetof(Manager, operational_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("CarrierState", "s", property_get_carrier_state, offsetof(Manager, carrier_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("CarrierState", "s", property_get_carrier_state, offsetof(Manager, carrier_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("AddressState", "s", property_get_address_state, offsetof(Manager, address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("AddressState", "s", property_get_address_state, offsetof(Manager, address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IPv4AddressState", "s", property_get_address_state, offsetof(Manager, ipv4_address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IPv6AddressState", "s", property_get_address_state, offsetof(Manager, ipv6_address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_METHOD_WITH_ARGS("ListLinks", SD_BUS_METHOD_WITH_ARGS("ListLinks",
SD_BUS_NO_ARGS, SD_BUS_NO_ARGS,

View File

@ -380,6 +380,7 @@ int manager_new(Manager **ret) {
*m = (Manager) { *m = (Manager) {
.speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL, .speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL,
.manage_foreign_routes = true, .manage_foreign_routes = true,
.manage_foreign_rules = true,
.ethtool_fd = -1, .ethtool_fd = -1,
}; };
@ -655,6 +656,9 @@ static int manager_enumerate_rules(Manager *m) {
assert(m); assert(m);
assert(m->rtnl); assert(m->rtnl);
if (!m->manage_foreign_rules)
return 0;
r = sd_rtnl_message_new_routing_policy_rule(m->rtnl, &req, RTM_GETRULE, 0); r = sd_rtnl_message_new_routing_policy_rule(m->rtnl, &req, RTM_GETRULE, 0);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -32,6 +32,7 @@ struct Manager {
bool dirty; bool dirty;
bool restarting; bool restarting;
bool manage_foreign_routes; bool manage_foreign_routes;
bool manage_foreign_rules;
Set *dirty_links; Set *dirty_links;
@ -39,6 +40,8 @@ struct Manager {
LinkOperationalState operational_state; LinkOperationalState operational_state;
LinkCarrierState carrier_state; LinkCarrierState carrier_state;
LinkAddressState address_state; LinkAddressState address_state;
LinkAddressState ipv4_address_state;
LinkAddressState ipv6_address_state;
Hashmap *links; Hashmap *links;
Hashmap *netdevs; Hashmap *netdevs;

View File

@ -67,6 +67,7 @@ Link.Promiscuous, config_parse_tristate,
Link.Unmanaged, config_parse_bool, 0, offsetof(Network, unmanaged) Link.Unmanaged, config_parse_bool, 0, offsetof(Network, unmanaged)
Link.ActivationPolicy, config_parse_activation_policy, 0, offsetof(Network, activation_policy) Link.ActivationPolicy, config_parse_activation_policy, 0, offsetof(Network, activation_policy)
Link.RequiredForOnline, config_parse_required_for_online, 0, 0 Link.RequiredForOnline, config_parse_required_for_online, 0, 0
Link.RequiredFamilyForOnline, config_parse_required_family_for_online, 0, offsetof(Network, required_family_for_online)
SR-IOV.VirtualFunction, config_parse_sr_iov_uint32, 0, 0 SR-IOV.VirtualFunction, config_parse_sr_iov_uint32, 0, 0
SR-IOV.VLANId, config_parse_sr_iov_uint32, 0, 0 SR-IOV.VLANId, config_parse_sr_iov_uint32, 0, 0
SR-IOV.QualityOfService, config_parse_sr_iov_uint32, 0, 0 SR-IOV.QualityOfService, config_parse_sr_iov_uint32, 0, 0

View File

@ -1196,6 +1196,9 @@ int config_parse_required_for_online(
return 0; return 0;
} }
DEFINE_CONFIG_PARSE_ENUM(config_parse_required_family_for_online, link_required_address_family, AddressFamily,
"Failed to parse RequiredFamilyForOnline= setting");
DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration, DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
"Failed to parse KeepConfiguration= setting"); "Failed to parse KeepConfiguration= setting");

View File

@ -104,6 +104,7 @@ struct Network {
bool unmanaged; bool unmanaged;
bool required_for_online; /* Is this network required to be considered online? */ bool required_for_online; /* Is this network required to be considered online? */
LinkOperationalStateRange required_operstate_for_online; LinkOperationalStateRange required_operstate_for_online;
AddressFamily required_family_for_online;
ActivationPolicy activation_policy; ActivationPolicy activation_policy;
/* misc settings */ /* misc settings */
@ -348,6 +349,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_timezone);
CONFIG_PARSER_PROTOTYPE(config_parse_dnssec_negative_trust_anchors); CONFIG_PARSER_PROTOTYPE(config_parse_dnssec_negative_trust_anchors);
CONFIG_PARSER_PROTOTYPE(config_parse_ntp); CONFIG_PARSER_PROTOTYPE(config_parse_ntp);
CONFIG_PARSER_PROTOTYPE(config_parse_required_for_online); CONFIG_PARSER_PROTOTYPE(config_parse_required_for_online);
CONFIG_PARSER_PROTOTYPE(config_parse_required_family_for_online);
CONFIG_PARSER_PROTOTYPE(config_parse_keep_configuration); CONFIG_PARSER_PROTOTYPE(config_parse_keep_configuration);
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_link_local_address_gen_mode); CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_link_local_address_gen_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_activation_policy); CONFIG_PARSER_PROTOTYPE(config_parse_activation_policy);

View File

@ -977,6 +977,8 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man
case RTM_NEWRULE: case RTM_NEWRULE:
if (rule) if (rule)
log_routing_policy_rule_debug(tmp, tmp->family, "Received remembered", NULL, m); log_routing_policy_rule_debug(tmp, tmp->family, "Received remembered", NULL, m);
else if (!m->manage_foreign_routes)
log_routing_policy_rule_debug(tmp, tmp->family, "Ignoring received foreign", NULL, m);
else { else {
log_routing_policy_rule_debug(tmp, tmp->family, "Remembering foreign", NULL, m); log_routing_policy_rule_debug(tmp, tmp->family, "Remembering foreign", NULL, m);
r = routing_policy_rule_consume_foreign(m, TAKE_PTR(tmp)); r = routing_policy_rule_consume_foreign(m, TAKE_PTR(tmp));

View File

@ -105,10 +105,11 @@ static int ordered_set_put_in4_addrv(
int manager_save(Manager *m) { int manager_save(Manager *m) {
_cleanup_ordered_set_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL; _cleanup_ordered_set_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL;
const char *operstate_str, *carrier_state_str, *address_state_str; const char *operstate_str, *carrier_state_str, *address_state_str, *ipv4_address_state_str, *ipv6_address_state_str;
LinkOperationalState operstate = LINK_OPERSTATE_OFF; LinkOperationalState operstate = LINK_OPERSTATE_OFF;
LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF; LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF;
LinkAddressState address_state = LINK_ADDRESS_STATE_OFF; LinkAddressState ipv4_address_state = LINK_ADDRESS_STATE_OFF, ipv6_address_state = LINK_ADDRESS_STATE_OFF,
address_state = LINK_ADDRESS_STATE_OFF;
_cleanup_(unlink_and_freep) char *temp_path = NULL; _cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_strv_free_ char **p = NULL; _cleanup_strv_free_ char **p = NULL;
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;
@ -133,6 +134,12 @@ int manager_save(Manager *m) {
if (link->address_state > address_state) if (link->address_state > address_state)
address_state = link->address_state; address_state = link->address_state;
if (link->ipv4_address_state > ipv4_address_state)
ipv4_address_state = link->ipv4_address_state;
if (link->ipv6_address_state > ipv6_address_state)
ipv6_address_state = link->ipv6_address_state;
if (!link->network) if (!link->network)
continue; continue;
@ -226,6 +233,12 @@ int manager_save(Manager *m) {
address_state_str = link_address_state_to_string(address_state); address_state_str = link_address_state_to_string(address_state);
assert(address_state_str); assert(address_state_str);
ipv4_address_state_str = link_address_state_to_string(ipv4_address_state);
assert(ipv4_address_state_str);
ipv6_address_state_str = link_address_state_to_string(ipv6_address_state);
assert(ipv6_address_state_str);
r = fopen_temporary(m->state_file, &f, &temp_path); r = fopen_temporary(m->state_file, &f, &temp_path);
if (r < 0) if (r < 0)
return r; return r;
@ -236,8 +249,10 @@ int manager_save(Manager *m) {
"# This is private data. Do not parse.\n" "# This is private data. Do not parse.\n"
"OPER_STATE=%s\n" "OPER_STATE=%s\n"
"CARRIER_STATE=%s\n" "CARRIER_STATE=%s\n"
"ADDRESS_STATE=%s\n", "ADDRESS_STATE=%s\n"
operstate_str, carrier_state_str, address_state_str); "IPV4_ADDRESS_STATE=%s\n"
"IPV6_ADDRESS_STATE=%s\n",
operstate_str, carrier_state_str, address_state_str, ipv4_address_state_str, ipv6_address_state_str);
ordered_set_print(f, "DNS=", dns); ordered_set_print(f, "DNS=", dns);
ordered_set_print(f, "NTP=", ntp); ordered_set_print(f, "NTP=", ntp);
@ -273,6 +288,18 @@ int manager_save(Manager *m) {
log_oom(); log_oom();
} }
if (m->ipv4_address_state != ipv4_address_state) {
m->ipv4_address_state = ipv4_address_state;
if (strv_extend(&p, "IPv4AddressState") < 0)
log_oom();
}
if (m->ipv6_address_state != ipv6_address_state) {
m->ipv6_address_state = ipv6_address_state;
if (strv_extend(&p, "IPv6AddressState") < 0)
log_oom();
}
if (p) { if (p) {
r = manager_send_changed_strv(m, p); r = manager_send_changed_strv(m, p);
if (r < 0) if (r < 0)
@ -376,7 +403,7 @@ static void serialize_addresses(
} }
int link_save(Link *link) { int link_save(Link *link) {
const char *admin_state, *oper_state, *carrier_state, *address_state; const char *admin_state, *oper_state, *carrier_state, *address_state, *ipv4_address_state, *ipv6_address_state;
_cleanup_(unlink_and_freep) char *temp_path = NULL; _cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;
int r; int r;
@ -403,6 +430,12 @@ int link_save(Link *link) {
address_state = link_address_state_to_string(link->address_state); address_state = link_address_state_to_string(link->address_state);
assert(address_state); assert(address_state);
ipv4_address_state = link_address_state_to_string(link->ipv4_address_state);
assert(ipv4_address_state);
ipv6_address_state = link_address_state_to_string(link->ipv6_address_state);
assert(ipv6_address_state);
r = fopen_temporary(link->state_file, &f, &temp_path); r = fopen_temporary(link->state_file, &f, &temp_path);
if (r < 0) if (r < 0)
return r; return r;
@ -414,8 +447,10 @@ int link_save(Link *link) {
"ADMIN_STATE=%s\n" "ADMIN_STATE=%s\n"
"OPER_STATE=%s\n" "OPER_STATE=%s\n"
"CARRIER_STATE=%s\n" "CARRIER_STATE=%s\n"
"ADDRESS_STATE=%s\n", "ADDRESS_STATE=%s\n"
admin_state, oper_state, carrier_state, address_state); "IPV4_ADDRESS_STATE=%s\n"
"IPV6_ADDRESS_STATE=%s\n",
admin_state, oper_state, carrier_state, address_state, ipv4_address_state, ipv6_address_state);
if (link->network) { if (link->network) {
char **dhcp6_domains = NULL, **dhcp_domains = NULL; char **dhcp6_domains = NULL, **dhcp_domains = NULL;
@ -431,6 +466,9 @@ int link_save(Link *link) {
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? ":" : "", st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? ":" : "",
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? strempty(link_operstate_to_string(st.max)) : ""); st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? strempty(link_operstate_to_string(st.max)) : "");
fprintf(f, "REQUIRED_FAMILY_FOR_ONLINE=%s\n",
link_required_address_family_to_string(link->network->required_family_for_online));
fprintf(f, "ACTIVATION_POLICY=%s\n", fprintf(f, "ACTIVATION_POLICY=%s\n",
activation_policy_to_string(link->network->activation_policy)); activation_policy_to_string(link->network->activation_policy));

View File

@ -8,18 +8,9 @@
#include "hashmap.h" #include "hashmap.h"
#include "log.h" #include "log.h"
#include "macro.h" #include "macro.h"
#include "network-util.h"
#include "string-util.h" #include "string-util.h"
typedef enum AddressFamily {
/* This is a bitmask, though it usually doesn't feel that way! */
ADDRESS_FAMILY_NO = 0,
ADDRESS_FAMILY_IPV4 = 1 << 0,
ADDRESS_FAMILY_IPV6 = 1 << 1,
ADDRESS_FAMILY_YES = ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6,
_ADDRESS_FAMILY_MAX,
_ADDRESS_FAMILY_INVALID = -EINVAL,
} AddressFamily;
typedef struct NetworkConfigSection { typedef struct NetworkConfigSection {
unsigned line; unsigned line;
bool invalid; bool invalid;

View File

@ -15,7 +15,9 @@
[Network] [Network]
#SpeedMeter=no #SpeedMeter=no
#SpeedMeterIntervalSec=10sec #SpeedMeterIntervalSec=10sec
#ManageForeignRoutingPolicyRules=yes
#ManageForeignRoutes=yes #ManageForeignRoutes=yes
#RouteTable=
[DHCP] [DHCP]
#DUIDType=vendor #DUIDType=vendor

View File

@ -97,7 +97,8 @@ int link_update_rtnl(Link *l, sd_netlink_message *m) {
} }
int link_update_monitor(Link *l) { int link_update_monitor(Link *l) {
_cleanup_free_ char *operstate = NULL, *required_operstate = NULL, *state = NULL; _cleanup_free_ char *operstate = NULL, *required_operstate = NULL, *required_family = NULL,
*ipv4_address_state = NULL, *ipv6_address_state = NULL, *state = NULL;
int r, ret = 0; int r, ret = 0;
assert(l); assert(l);
@ -135,6 +136,47 @@ int link_update_monitor(Link *l) {
l->operational_state = s; l->operational_state = s;
} }
r = sd_network_link_get_required_family_for_online(l->ifindex, &required_family);
if (r < 0)
ret = log_link_debug_errno(l, r, "Failed to get required address family, ignoring: %m");
else if (isempty(required_family))
l->required_family = ADDRESS_FAMILY_NO;
else {
AddressFamily f;
f = link_required_address_family_from_string(required_family);
if (f < 0)
ret = log_link_debug_errno(l, f, "Failed to parse required address family, ignoring: %m");
else
l->required_family = f;
}
r = sd_network_link_get_ipv4_address_state(l->ifindex, &ipv4_address_state);
if (r < 0)
ret = log_link_debug_errno(l, r, "Failed to get IPv4 address state, ignoring: %m");
else {
LinkAddressState s;
s = link_address_state_from_string(ipv4_address_state);
if (s < 0)
ret = log_link_debug_errno(l, s, "Failed to parse IPv4 address state, ignoring: %m");
else
l->ipv4_address_state = s;
}
r = sd_network_link_get_ipv6_address_state(l->ifindex, &ipv6_address_state);
if (r < 0)
ret = log_link_debug_errno(l, r, "Failed to get IPv6 address state, ignoring: %m");
else {
LinkAddressState s;
s = link_address_state_from_string(ipv6_address_state);
if (s < 0)
ret = log_link_debug_errno(l, s, "Failed to parse IPv6 address state, ignoring: %m");
else
l->ipv6_address_state = s;
}
r = sd_network_link_get_setup_state(l->ifindex, &state); r = sd_network_link_get_setup_state(l->ifindex, &state);
if (r < 0) if (r < 0)
ret = log_link_debug_errno(l, r, "Failed to get setup state, ignoring: %m"); ret = log_link_debug_errno(l, r, "Failed to get setup state, ignoring: %m");

View File

@ -19,6 +19,9 @@ struct Link {
bool required_for_online; bool required_for_online;
LinkOperationalStateRange required_operstate; LinkOperationalStateRange required_operstate;
LinkOperationalState operational_state; LinkOperationalState operational_state;
AddressFamily required_family;
LinkAddressState ipv4_address_state;
LinkAddressState ipv6_address_state;
char *state; char *state;
}; };

View File

@ -32,6 +32,13 @@ static bool manager_ignore_link(Manager *m, Link *link) {
} }
static int manager_link_is_online(Manager *m, Link *l, LinkOperationalStateRange s) { static int manager_link_is_online(Manager *m, Link *l, LinkOperationalStateRange s) {
AddressFamily required_family;
bool needs_ipv4;
bool needs_ipv6;
assert(m);
assert(l);
/* This returns the following: /* This returns the following:
* -EAGAIN: not processed by udev or networkd * -EAGAIN: not processed by udev or networkd
* 0: operstate is not enough * 0: operstate is not enough
@ -60,7 +67,35 @@ static int manager_link_is_online(Manager *m, Link *l, LinkOperationalStateRange
return 0; return 0;
} }
required_family = m->required_family > 0 ? m->required_family : l->required_family;
needs_ipv4 = required_family & ADDRESS_FAMILY_IPV4;
needs_ipv6 = required_family & ADDRESS_FAMILY_IPV6;
if (s.min >= LINK_OPERSTATE_DEGRADED) {
if (needs_ipv4 && l->ipv4_address_state < LINK_ADDRESS_STATE_DEGRADED)
goto ipv4_not_ready;
if (needs_ipv6 && l->ipv6_address_state < LINK_ADDRESS_STATE_DEGRADED)
goto ipv6_not_ready;
}
if (s.min >= LINK_OPERSTATE_ROUTABLE) {
if (needs_ipv4 && l->ipv4_address_state < LINK_ADDRESS_STATE_ROUTABLE)
goto ipv4_not_ready;
if (needs_ipv6 && l->ipv6_address_state < LINK_ADDRESS_STATE_ROUTABLE)
goto ipv6_not_ready;
}
return 1; return 1;
ipv4_not_ready:
log_link_debug(l, "No routable or link-local IPv4 address is configured.");
return 0;
ipv6_not_ready:
log_link_debug(l, "No routable or link-local IPv6 address is configured.");
return 0;
} }
bool manager_configured(Manager *m) { bool manager_configured(Manager *m) {
@ -298,6 +333,7 @@ static int manager_network_monitor_listen(Manager *m) {
int manager_new(Manager **ret, Hashmap *interfaces, char **ignore, int manager_new(Manager **ret, Hashmap *interfaces, char **ignore,
LinkOperationalStateRange required_operstate, LinkOperationalStateRange required_operstate,
AddressFamily required_family,
bool any, usec_t timeout) { bool any, usec_t timeout) {
_cleanup_(manager_freep) Manager *m = NULL; _cleanup_(manager_freep) Manager *m = NULL;
int r; int r;
@ -312,6 +348,7 @@ int manager_new(Manager **ret, Hashmap *interfaces, char **ignore,
.interfaces = interfaces, .interfaces = interfaces,
.ignore = ignore, .ignore = ignore,
.required_operstate = required_operstate, .required_operstate = required_operstate,
.required_family = required_family,
.any = any, .any = any,
}; };

View File

@ -21,6 +21,7 @@ struct Manager {
char **ignore; char **ignore;
LinkOperationalStateRange required_operstate; LinkOperationalStateRange required_operstate;
AddressFamily required_family;
bool any; bool any;
sd_netlink *rtnl; sd_netlink *rtnl;
@ -35,6 +36,7 @@ struct Manager {
Manager* manager_free(Manager *m); Manager* manager_free(Manager *m);
int manager_new(Manager **ret, Hashmap *interfaces, char **ignore, int manager_new(Manager **ret, Hashmap *interfaces, char **ignore,
LinkOperationalStateRange required_operstate, LinkOperationalStateRange required_operstate,
AddressFamily required_family,
bool any, usec_t timeout); bool any, usec_t timeout);
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);

View File

@ -19,6 +19,7 @@ static usec_t arg_timeout = 120 * USEC_PER_SEC;
static Hashmap *arg_interfaces = NULL; static Hashmap *arg_interfaces = NULL;
static char **arg_ignore = NULL; static char **arg_ignore = NULL;
static LinkOperationalStateRange arg_required_operstate = { _LINK_OPERSTATE_INVALID, _LINK_OPERSTATE_INVALID }; static LinkOperationalStateRange arg_required_operstate = { _LINK_OPERSTATE_INVALID, _LINK_OPERSTATE_INVALID };
static AddressFamily arg_required_family = ADDRESS_FAMILY_NO;
static bool arg_any = false; static bool arg_any = false;
STATIC_DESTRUCTOR_REGISTER(arg_interfaces, hashmap_free_free_freep); STATIC_DESTRUCTOR_REGISTER(arg_interfaces, hashmap_free_free_freep);
@ -42,6 +43,8 @@ static int help(void) {
" --ignore=INTERFACE Don't take these interfaces into account\n" " --ignore=INTERFACE Don't take these interfaces into account\n"
" -o --operational-state=MIN_OPERSTATE[:MAX_OPERSTATE]\n" " -o --operational-state=MIN_OPERSTATE[:MAX_OPERSTATE]\n"
" Required operational state\n" " Required operational state\n"
" -4 --ipv4 Requires at least one IPv4 address\n"
" -6 --ipv6 Requires at least one IPv6 address\n"
" --any Wait until at least one of the interfaces is online\n" " --any Wait until at least one of the interfaces is online\n"
" --timeout=SECS Maximum time to wait for network connectivity\n" " --timeout=SECS Maximum time to wait for network connectivity\n"
"\nSee the %s for details.\n", "\nSee the %s for details.\n",
@ -111,6 +114,8 @@ static int parse_argv(int argc, char *argv[]) {
{ "interface", required_argument, NULL, 'i' }, { "interface", required_argument, NULL, 'i' },
{ "ignore", required_argument, NULL, ARG_IGNORE }, { "ignore", required_argument, NULL, ARG_IGNORE },
{ "operational-state", required_argument, NULL, 'o' }, { "operational-state", required_argument, NULL, 'o' },
{ "ipv4", no_argument, NULL, '4' },
{ "ipv6", no_argument, NULL, '6' },
{ "any", no_argument, NULL, ARG_ANY }, { "any", no_argument, NULL, ARG_ANY },
{ "timeout", required_argument, NULL, ARG_TIMEOUT }, { "timeout", required_argument, NULL, ARG_TIMEOUT },
{} {}
@ -121,7 +126,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0); assert(argc >= 0);
assert(argv); assert(argv);
while ((c = getopt_long(argc, argv, "hi:qo:", options, NULL)) >= 0) while ((c = getopt_long(argc, argv, "hi:qo:46", options, NULL)) >= 0)
switch (c) { switch (c) {
@ -159,6 +164,15 @@ static int parse_argv(int argc, char *argv[]) {
break; break;
} }
case '4':
arg_required_family |= ADDRESS_FAMILY_IPV4;
break;
case '6':
arg_required_family |= ADDRESS_FAMILY_IPV6;
break;
case ARG_ANY: case ARG_ANY:
arg_any = true; arg_any = true;
break; break;
@ -197,7 +211,7 @@ static int run(int argc, char *argv[]) {
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0); assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
r = manager_new(&m, arg_interfaces, arg_ignore, arg_required_operstate, arg_any, arg_timeout); r = manager_new(&m, arg_interfaces, arg_ignore, arg_required_operstate, arg_required_family, arg_any, arg_timeout);
if (r < 0) if (r < 0)
return log_error_errno(r, "Could not create manager: %m"); return log_error_errno(r, "Could not create manager: %m");

View File

@ -51,6 +51,8 @@ _SD_BEGIN_DECLARATIONS;
int sd_network_get_operational_state(char **state); int sd_network_get_operational_state(char **state);
int sd_network_get_carrier_state(char **state); int sd_network_get_carrier_state(char **state);
int sd_network_get_address_state(char **state); int sd_network_get_address_state(char **state);
int sd_network_get_ipv4_address_state(char **state);
int sd_network_get_ipv6_address_state(char **state);
/* Get DNS entries for all links. These are string representations of /* Get DNS entries for all links. These are string representations of
* IP addresses */ * IP addresses */
@ -92,8 +94,11 @@ int sd_network_link_get_setup_state(int ifindex, char **state);
*/ */
int sd_network_link_get_operational_state(int ifindex, char **state); int sd_network_link_get_operational_state(int ifindex, char **state);
int sd_network_link_get_required_operstate_for_online(int ifindex, char **state); int sd_network_link_get_required_operstate_for_online(int ifindex, char **state);
int sd_network_link_get_required_family_for_online(int ifindex, char **state);
int sd_network_link_get_carrier_state(int ifindex, char **state); int sd_network_link_get_carrier_state(int ifindex, char **state);
int sd_network_link_get_address_state(int ifindex, char **state); int sd_network_link_get_address_state(int ifindex, char **state);
int sd_network_link_get_ipv4_address_state(int ifindex, char **state);
int sd_network_link_get_ipv6_address_state(int ifindex, char **state);
/* Indicates whether the network is relevant to being online. /* Indicates whether the network is relevant to being online.
* Possible return codes: * Possible return codes:

View File

@ -23,6 +23,7 @@ test_append_files() {
install_dmevent install_dmevent
generate_module_dependencies generate_module_dependencies
inst_binary losetup inst_binary losetup
inst_binary wc
install_verity_minimal install_verity_minimal
) )
} }

View File

@ -32,6 +32,7 @@ PermanentMACAddress=
[Link] [Link]
ActivationPolicy= ActivationPolicy=
RequiredForOnline= RequiredForOnline=
RequiredFamilyForOnline=
ARP= ARP=
AllMulticast= AllMulticast=
Unmanaged= Unmanaged=

View File

@ -545,6 +545,7 @@ RemoteChecksumRx=
RemoteChecksumTx= RemoteChecksumTx=
ReorderHeader= ReorderHeader=
RequestBroadcast= RequestBroadcast=
RequiredFamilyForOnline=
RequiredForOnline= RequiredForOnline=
ResendIGMP= ResendIGMP=
RootDistanceMaxSec= RootDistanceMaxSec=

View File

@ -0,0 +1,9 @@
[Match]
Name=veth99
[NetworkEmulator]
DelaySec=9
[Network]
DHCP=ipv4
IPv6AcceptRA=true

View File

@ -0,0 +1,11 @@
[Match]
Name=veth-peer
[Network]
Address=192.168.5.1/24
IPv6AcceptRA=no
DHCPServer=yes
IPv6SendRA=yes
[IPv6Prefix]
Prefix=2002:da8:1:0::/64

View File

@ -0,0 +1,12 @@
[Match]
Name=veth-peer
[NetworkEmulator]
DelaySec=15
[Network]
IPv6AcceptRA=no
IPv6SendRA=yes
[IPv6Prefix]
Prefix=2002:da8:1:0::/64

View File

@ -0,0 +1,6 @@
[Match]
Name=veth99
[Network]
IPv6AcceptRA=true
Address=192.168.5.1/24

View File

@ -3,6 +3,7 @@ Name=dummy98
[Link] [Link]
RequiredForOnline=routable RequiredForOnline=routable
RequiredFamilyForOnline=both
[Network] [Network]
IPv6AcceptRA=no IPv6AcceptRA=no
@ -14,3 +15,4 @@ MulticastDNS=yes
DNSSEC=no DNSSEC=no
Address=192.168.10.10/24 Address=192.168.10.10/24
Address=192.168.12.12/24 Address=192.168.12.12/24
Address=2002:da8:1:0:1034:56ff:fe78:9abc/64

View File

@ -555,7 +555,7 @@ class Utilities():
self.fail(f'Timed out waiting for {link} to reach state {operstate}/{setup_state}') self.fail(f'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
return False return False
def wait_online(self, links_with_operstate, timeout='20s', bool_any=False, setup_state='configured', setup_timeout=5): def wait_online(self, links_with_operstate, timeout='20s', bool_any=False, ipv4=False, ipv6=False, setup_state='configured', setup_timeout=5):
"""Wait for the link(s) to reach the specified operstate and/or setup state. """Wait for the link(s) to reach the specified operstate and/or setup state.
This is similar to wait_operstate() but can be used for multiple links, This is similar to wait_operstate() but can be used for multiple links,
@ -569,6 +569,9 @@ class Utilities():
Set 'bool_any' to True to wait for any (instead of all) of the given links. Set 'bool_any' to True to wait for any (instead of all) of the given links.
If this is set, no setup_state checks are done. If this is set, no setup_state checks are done.
Set 'ipv4' or 'ipv6' to True to wait for IPv4 address or IPv6 address, respectively, of each of the given links.
This is applied only for the operational state 'degraded' or above.
Note that this function waits for the link(s) to reach *or exceed* the given operstate. Note that this function waits for the link(s) to reach *or exceed* the given operstate.
However, the setup_state, if specified, must be matched *exactly*. However, the setup_state, if specified, must be matched *exactly*.
@ -578,6 +581,10 @@ class Utilities():
args = wait_online_cmd + [f'--timeout={timeout}'] + [f'--interface={link}' for link in links_with_operstate] args = wait_online_cmd + [f'--timeout={timeout}'] + [f'--interface={link}' for link in links_with_operstate]
if bool_any: if bool_any:
args += ['--any'] args += ['--any']
if ipv4:
args += ['--ipv4']
if ipv6:
args += ['--ipv6']
try: try:
check_output(*args, env=env) check_output(*args, env=env)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
@ -1781,6 +1788,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
'gretun97', 'gretun97',
'ip6gretun97', 'ip6gretun97',
'test1', 'test1',
'veth-peer',
'veth99', 'veth99',
'vrf99', 'vrf99',
] ]
@ -1842,6 +1850,10 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
'25-vrf.netdev', '25-vrf.netdev',
'25-vrf.network', '25-vrf.network',
'26-link-local-addressing-ipv6.network', '26-link-local-addressing-ipv6.network',
'dhcp-client-ipv4-ipv6ra-prefix-client-with-delay.network',
'dhcp-server-with-ipv6-prefix.network',
'ipv6ra-prefix-client-with-static-ipv4-address.network',
'ipv6-prefix-with-delay.network',
'routing-policy-rule-dummy98.network', 'routing-policy-rule-dummy98.network',
'routing-policy-rule-test1.network', 'routing-policy-rule-test1.network',
'routing-policy-rule-reconfigure1.network', 'routing-policy-rule-reconfigure1.network',
@ -3099,6 +3111,22 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
call('rmmod netdevsim', stderr=subprocess.DEVNULL) call('rmmod netdevsim', stderr=subprocess.DEVNULL)
def test_wait_online_ipv4(self):
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-with-ipv6-prefix.network', 'dhcp-client-ipv4-ipv6ra-prefix-client-with-delay.network')
start_networkd()
self.wait_online(['veth99:routable'], ipv4=True)
self.wait_address('veth99', r'192.168.5.[0-9]+', ipv='-4', timeout_sec=1)
def test_wait_online_ipv6(self):
copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix-with-delay.network', 'ipv6ra-prefix-client-with-static-ipv4-address.network')
start_networkd()
self.wait_online(['veth99:routable'], ipv6=True)
self.wait_address('veth99', r'2002:da8:1:0:1034:56ff:fe78:9abc', ipv='-6', timeout_sec=1)
class NetworkdStateFileTests(unittest.TestCase, Utilities): class NetworkdStateFileTests(unittest.TestCase, Utilities):
links = [ links = [
'dummy98', 'dummy98',
@ -3135,10 +3163,13 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities):
with open(path) as f: with open(path) as f:
data = f.read() data = f.read()
self.assertRegex(data, r'IPV4_ADDRESS_STATE=routable')
self.assertRegex(data, r'IPV6_ADDRESS_STATE=routable')
self.assertRegex(data, r'ADMIN_STATE=configured') self.assertRegex(data, r'ADMIN_STATE=configured')
self.assertRegex(data, r'OPER_STATE=routable') self.assertRegex(data, r'OPER_STATE=routable')
self.assertRegex(data, r'REQUIRED_FOR_ONLINE=yes') self.assertRegex(data, r'REQUIRED_FOR_ONLINE=yes')
self.assertRegex(data, r'REQUIRED_OPER_STATE_FOR_ONLINE=routable') self.assertRegex(data, r'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
self.assertRegex(data, r'REQUIRED_FAMILY_FOR_ONLINE=both')
self.assertRegex(data, r'ACTIVATION_POLICY=up') self.assertRegex(data, r'ACTIVATION_POLICY=up')
self.assertRegex(data, r'NETWORK_FILE=/run/systemd/network/state-file-tests.network') self.assertRegex(data, r'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
self.assertRegex(data, r'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com') self.assertRegex(data, r'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')

View File

@ -1,13 +1,13 @@
#!/usr/bin/env bash #!/usr/bin/env bash
#set -ex set -eux
#set -o pipefail set -o pipefail
NPROC=$(nproc) NPROC=$(nproc)
MAX_QUEUE_SIZE=${NPROC:-2} MAX_QUEUE_SIZE=${NPROC:-2}
IFS=$'\n' TEST_LIST=($(ls /usr/lib/systemd/tests/test-*)) mapfile -t TEST_LIST < <(find /usr/lib/systemd/tests/ -maxdepth 1 -type f -name "test-*")
# reset state # reset state
rm /failed-tests /skipped-tests /skipped rm -fv /failed-tests /skipped-tests /skipped
# Check & report test results # Check & report test results
# Arguments: # Arguments:
@ -54,10 +54,9 @@ for task in "${TEST_LIST[@]}"; do
# until one of the tasks finishes, so we can replace it. # until one of the tasks finishes, so we can replace it.
while [[ ${#running[@]} -ge $MAX_QUEUE_SIZE ]]; do while [[ ${#running[@]} -ge $MAX_QUEUE_SIZE ]]; do
for key in "${!running[@]}"; do for key in "${!running[@]}"; do
if ! kill -0 ${running[$key]} &>/dev/null; then if ! kill -0 "${running[$key]}" &>/dev/null; then
# Task has finished, report its result and drop it from the queue # Task has finished, report its result and drop it from the queue
wait ${running[$key]} wait "${running[$key]}" && ec=0 || ec=$?
ec=$?
report_result "$key" $ec report_result "$key" $ec
unset running["$key"] unset running["$key"]
# Break from inner for loop and outer while loop to skip # Break from inner for loop and outer while loop to skip

View File

@ -1,5 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail
# Test merging of a --job-mode=ignore-dependencies job into a previously # Test merging of a --job-mode=ignore-dependencies job into a previously
# installed job. # installed job.
@ -17,7 +18,7 @@ grep 'hello\.service.*waiting' /root/list-jobs.txt
START_SEC=$(date -u '+%s') START_SEC=$(date -u '+%s')
systemctl start --job-mode=ignore-dependencies hello systemctl start --job-mode=ignore-dependencies hello
END_SEC=$(date -u '+%s') END_SEC=$(date -u '+%s')
ELAPSED=$(($END_SEC-$START_SEC)) ELAPSED=$((END_SEC-START_SEC))
test "$ELAPSED" -lt 3 test "$ELAPSED" -lt 3
@ -75,14 +76,14 @@ EOF
START_SEC=$(date -u '+%s') START_SEC=$(date -u '+%s')
systemctl start --wait wait2.service systemctl start --wait wait2.service
END_SEC=$(date -u '+%s') END_SEC=$(date -u '+%s')
ELAPSED=$(($END_SEC-$START_SEC)) ELAPSED=$((END_SEC-START_SEC))
[[ "$ELAPSED" -ge 2 ]] && [[ "$ELAPSED" -le 4 ]] || exit 1 [[ "$ELAPSED" -ge 2 ]] && [[ "$ELAPSED" -le 4 ]] || exit 1
# wait5fail fails, so systemctl should fail # wait5fail fails, so systemctl should fail
START_SEC=$(date -u '+%s') START_SEC=$(date -u '+%s')
systemctl start --wait wait2.service wait5fail.service && { echo 'unexpected success'; exit 1; } systemctl start --wait wait2.service wait5fail.service && { echo 'unexpected success'; exit 1; }
END_SEC=$(date -u '+%s') END_SEC=$(date -u '+%s')
ELAPSED=$(($END_SEC-$START_SEC)) ELAPSED=$((END_SEC-START_SEC))
[[ "$ELAPSED" -ge 5 ]] && [[ "$ELAPSED" -le 7 ]] || exit 1 [[ "$ELAPSED" -ge 5 ]] && [[ "$ELAPSED" -le 7 ]] || exit 1
# Test time-limited scopes # Test time-limited scopes
@ -91,7 +92,7 @@ set +e
systemd-run --scope --property=RuntimeMaxSec=3s sleep 10 systemd-run --scope --property=RuntimeMaxSec=3s sleep 10
RESULT=$? RESULT=$?
END_SEC=$(date -u '+%s') END_SEC=$(date -u '+%s')
ELAPSED=$(($END_SEC-$START_SEC)) ELAPSED=$((END_SEC-START_SEC))
[[ "$ELAPSED" -ge 3 ]] && [[ "$ELAPSED" -le 5 ]] || exit 1 [[ "$ELAPSED" -ge 3 ]] && [[ "$ELAPSED" -le 5 ]] || exit 1
[[ "$RESULT" -ne 0 ]] || exit 1 [[ "$RESULT" -ne 0 ]] || exit 1

View File

@ -1,20 +1,19 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -x set -eux
set -e
set -o pipefail set -o pipefail
# Test stdout stream # Test stdout stream
# Skip empty lines # Skip empty lines
ID=$(journalctl --new-id128 | sed -n 2p) ID=$(journalctl --new-id128 | sed -n 2p)
>/expected : >/expected
printf $'\n\n\n' | systemd-cat -t "$ID" --level-prefix false printf $'\n\n\n' | systemd-cat -t "$ID" --level-prefix false
journalctl --sync journalctl --sync
journalctl -b -o cat -t "$ID" >/output journalctl -b -o cat -t "$ID" >/output
cmp /expected /output cmp /expected /output
ID=$(journalctl --new-id128 | sed -n 2p) ID=$(journalctl --new-id128 | sed -n 2p)
>/expected : >/expected
printf $'<5>\n<6>\n<7>\n' | systemd-cat -t "$ID" --level-prefix true printf $'<5>\n<6>\n<7>\n' | systemd-cat -t "$ID" --level-prefix true
journalctl --sync journalctl --sync
journalctl -b -o cat -t "$ID" >/output journalctl -b -o cat -t "$ID" >/output
@ -55,7 +54,7 @@ ID=$(journalctl --new-id128 | sed -n 2p)
printf $'foo' | systemd-cat -t "$ID" --level-prefix false printf $'foo' | systemd-cat -t "$ID" --level-prefix false
journalctl --sync journalctl --sync
journalctl -b -o export --output-fields=MESSAGE,FOO --output-fields=PRIORITY,MESSAGE -t "$ID" >/output journalctl -b -o export --output-fields=MESSAGE,FOO --output-fields=PRIORITY,MESSAGE -t "$ID" >/output
[[ `grep -c . /output` -eq 6 ]] [[ $(grep -c . /output) -eq 6 ]]
grep -q '^__CURSOR=' /output grep -q '^__CURSOR=' /output
grep -q '^MESSAGE=foo$' /output grep -q '^MESSAGE=foo$' /output
grep -q '^PRIORITY=6$' /output grep -q '^PRIORITY=6$' /output
@ -83,7 +82,7 @@ journalctl --sync
# We can drop this grep when https://github.com/systemd/systemd/issues/13937 # We can drop this grep when https://github.com/systemd/systemd/issues/13937
# has a fix. # has a fix.
journalctl -b -o export -t "$ID" --output-fields=_PID | grep '^_PID=' >/output journalctl -b -o export -t "$ID" --output-fields=_PID | grep '^_PID=' >/output
[[ `grep -c . /output` -eq 2 ]] [[ $(grep -c . /output) -eq 2 ]]
grep -q "^_PID=$PID" /output grep -q "^_PID=$PID" /output
grep -vq "^_PID=$PID" /output grep -vq "^_PID=$PID" /output

View File

@ -1,6 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -x set -eux
set -e
set -o pipefail set -o pipefail
P=/run/systemd/system.conf.d P=/run/systemd/system.conf.d
@ -19,7 +18,9 @@ systemctl daemon-reload
[[ "$(systemctl show -P LimitNOFILESoft testsuite-05.service)" = "10000" ]] [[ "$(systemctl show -P LimitNOFILESoft testsuite-05.service)" = "10000" ]]
[[ "$(systemctl show -P LimitNOFILE testsuite-05.service)" = "16384" ]] [[ "$(systemctl show -P LimitNOFILE testsuite-05.service)" = "16384" ]]
# shellcheck disable=SC2016
systemd-run --wait -t bash -c '[[ "$(ulimit -n -S)" = "10000" ]]' systemd-run --wait -t bash -c '[[ "$(ulimit -n -S)" = "10000" ]]'
# shellcheck disable=SC2016
systemd-run --wait -t bash -c '[[ "$(ulimit -n -H)" = "16384" ]]' systemd-run --wait -t bash -c '[[ "$(ulimit -n -H)" = "16384" ]]'
touch /testok touch /testok

View File

@ -1,6 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -x set -eux
set -e
set -o pipefail set -o pipefail
echo 1 >/sys/fs/selinux/enforce || { echo 1 >/sys/fs/selinux/enforce || {

View File

@ -1,31 +1,31 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -x set -eux
set -e set -o pipefail
>/failed : >/failed
cat <<'EOL' >/lib/systemd/system/my.service cat >/lib/systemd/system/my.service <<EOF
[Service] [Service]
Type=oneshot Type=oneshot
ExecStart=/bin/echo Timer runs me ExecStart=/bin/echo Timer runs me
EOL EOF
cat <<'EOL' >/lib/systemd/system/my.timer cat >/lib/systemd/system/my.timer <<EOF
[Timer] [Timer]
OnBootSec=10s OnBootSec=10s
OnUnitInactiveSec=1h OnUnitInactiveSec=1h
EOL EOF
systemctl unmask my.timer systemctl unmask my.timer
systemctl start my.timer systemctl start my.timer
mkdir -p /etc/systemd/system/my.timer.d/ mkdir -p /etc/systemd/system/my.timer.d/
cat <<'EOL' >/etc/systemd/system/my.timer.d/override.conf cat >/etc/systemd/system/my.timer.d/override.conf <<EOF
[Timer] [Timer]
OnBootSec=10s OnBootSec=10s
OnUnitInactiveSec=1h OnUnitInactiveSec=1h
EOL EOF
systemctl daemon-reload systemctl daemon-reload

View File

@ -1,7 +1,8 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -x set -eux
set -o pipefail
systemctl start fail-on-restart.service systemctl --no-block start fail-on-restart.service
active_state=$(systemctl show --value --property ActiveState fail-on-restart.service) active_state=$(systemctl show --value --property ActiveState fail-on-restart.service)
while [[ "$active_state" == "activating" || "$active_state" == "active" ]]; do while [[ "$active_state" == "activating" || "$active_state" == "active" ]]; do
sleep 1 sleep 1

View File

@ -1,10 +1,9 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -x set -eux
set -e
set -o pipefail set -o pipefail
U=/run/systemd/system/test12.socket U=/run/systemd/system/test12.socket
cat <<'EOF' >$U cat >$U <<EOF
[Unit] [Unit]
Description=Test 12 socket Description=Test 12 socket
[Socket] [Socket]
@ -14,7 +13,7 @@ SocketGroup=adm
SocketMode=0660 SocketMode=0660
EOF EOF
cat <<'EOF' >/run/systemd/system/test12@.service cat >/run/systemd/system/test12@.service <<EOF
[Unit] [Unit]
Description=Test service Description=Test service
[Service] [Service]

View File

@ -1,7 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -x # shellcheck disable=SC2016
set -e set -eux
set -u
set -o pipefail set -o pipefail
export SYSTEMD_LOG_LEVEL=debug export SYSTEMD_LOG_LEVEL=debug
@ -31,10 +30,10 @@ if unshare -U sh -c :; then
is_user_ns_supported=yes is_user_ns_supported=yes
fi fi
SUSE_OPTS="" SUSE_OPTS=()
ID_LIKE=$(awk -F= '$1=="ID_LIKE" { print $2 ;}' /etc/os-release) ID_LIKE=$(awk -F= '$1=="ID_LIKE" { print $2 ;}' /etc/os-release)
if [[ "$ID_LIKE" = *"suse"* ]]; then if [[ "$ID_LIKE" = *"suse"* ]]; then
SUSE_OPTS="--bind /lib64 --bind /usr/lib64 " SUSE_OPTS+=(--bind /lib64 --bind /usr/lib64)
fi fi
function check_bind_tmp_path { function check_bind_tmp_path {
@ -42,8 +41,8 @@ function check_bind_tmp_path {
local _root="/var/lib/machines/testsuite-13.bind-tmp-path" local _root="/var/lib/machines/testsuite-13.bind-tmp-path"
rm -rf "$_root" rm -rf "$_root"
/usr/lib/systemd/tests/testdata/create-busybox-container "$_root" /usr/lib/systemd/tests/testdata/create-busybox-container "$_root"
>/tmp/bind : >/tmp/bind
systemd-nspawn $SUSE_OPTS--register=no -D "$_root" --bind=/tmp/bind /bin/sh -c 'test -e /tmp/bind' systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" --bind=/tmp/bind /bin/sh -c 'test -e /tmp/bind'
} }
function check_norbind { function check_norbind {
@ -55,15 +54,15 @@ function check_norbind {
mount -t tmpfs tmpfs /tmp/binddir/subdir mount -t tmpfs tmpfs /tmp/binddir/subdir
echo -n "inner" >/tmp/binddir/subdir/file echo -n "inner" >/tmp/binddir/subdir/file
/usr/lib/systemd/tests/testdata/create-busybox-container "$_root" /usr/lib/systemd/tests/testdata/create-busybox-container "$_root"
systemd-nspawn $SUSE_OPTS--register=no -D "$_root" --bind=/tmp/binddir:/mnt:norbind /bin/sh -c 'CONTENT=$(cat /mnt/subdir/file); if [[ $CONTENT != "outer" ]]; then echo "*** unexpected content: $CONTENT"; return 1; fi' systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" --bind=/tmp/binddir:/mnt:norbind /bin/sh -c 'CONTENT=$(cat /mnt/subdir/file); if [[ $CONTENT != "outer" ]]; then echo "*** unexpected content: $CONTENT"; return 1; fi'
} }
function check_notification_socket { function check_notification_socket {
# https://github.com/systemd/systemd/issues/4944 # https://github.com/systemd/systemd/issues/4944
local _cmd='echo a | $(busybox which nc) -U -u -w 1 /run/host/notify' local _cmd='echo a | $(busybox which nc) -U -u -w 1 /run/host/notify'
# /testsuite-13.nc-container is prepared by test.sh # /testsuite-13.nc-container is prepared by test.sh
systemd-nspawn $SUSE_OPTS--register=no -D /testsuite-13.nc-container /bin/sh -x -c "$_cmd" systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D /testsuite-13.nc-container /bin/sh -x -c "$_cmd"
systemd-nspawn $SUSE_OPTS--register=no -D /testsuite-13.nc-container -U /bin/sh -x -c "$_cmd" systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D /testsuite-13.nc-container -U /bin/sh -x -c "$_cmd"
} }
function check_os_release { function check_os_release {
@ -77,15 +76,15 @@ if echo test >>/run/host/os-release; then exit 1; fi
' '
local _os_release_source="/etc/os-release" local _os_release_source="/etc/os-release"
if [ ! -r "${_os_release_source}" ]; then if [[ ! -r "${_os_release_source}" ]]; then
_os_release_source="/usr/lib/os-release" _os_release_source="/usr/lib/os-release"
elif [ -L "${_os_release_source}" ] && rm /etc/os-release; then elif [[ -L "${_os_release_source}" ]] && rm /etc/os-release; then
# Ensure that /etc always wins if available # Ensure that /etc always wins if available
cp /usr/lib/os-release /etc cp /usr/lib/os-release /etc
echo MARKER=1 >>/etc/os-release echo MARKER=1 >>/etc/os-release
fi fi
systemd-nspawn $SUSE_OPTS--register=no -D /testsuite-13.nc-container --bind="${_os_release_source}":/tmp/os-release /bin/sh -x -e -c "$_cmd" systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D /testsuite-13.nc-container --bind="${_os_release_source}":/tmp/os-release /bin/sh -x -e -c "$_cmd"
if grep -q MARKER /etc/os-release; then if grep -q MARKER /etc/os-release; then
rm /etc/os-release rm /etc/os-release
@ -96,10 +95,10 @@ if echo test >>/run/host/os-release; then exit 1; fi
function check_machinectl_bind { function check_machinectl_bind {
local _cmd='for i in $(seq 1 20); do if test -f /tmp/marker; then exit 0; fi; sleep 0.5; done; exit 1;' local _cmd='for i in $(seq 1 20); do if test -f /tmp/marker; then exit 0; fi; sleep 0.5; done; exit 1;'
cat <<EOF >/run/systemd/system/nspawn_machinectl_bind.service cat >/run/systemd/system/nspawn_machinectl_bind.service <<EOF
[Service] [Service]
Type=notify Type=notify
ExecStart=systemd-nspawn $SUSE_OPTS -D /testsuite-13.nc-container --notify-ready=no /bin/sh -x -e -c "$_cmd" ExecStart=systemd-nspawn ${SUSE_OPTS[@]} -D /testsuite-13.nc-container --notify-ready=no /bin/sh -x -e -c "$_cmd"
EOF EOF
systemctl start nspawn_machinectl_bind.service systemctl start nspawn_machinectl_bind.service
@ -113,7 +112,7 @@ EOF
sleep 0.1 sleep 0.1
done done
return $(systemctl show -P ExecMainStatus nspawn_machinectl_bind.service) return "$(systemctl show -P ExecMainStatus nspawn_machinectl_bind.service)"
} }
function run { function run {
@ -129,65 +128,54 @@ function run {
local _root="/var/lib/machines/testsuite-13.unified-$1-cgns-$2-api-vfs-writable-$3" local _root="/var/lib/machines/testsuite-13.unified-$1-cgns-$2-api-vfs-writable-$3"
rm -rf "$_root" rm -rf "$_root"
/usr/lib/systemd/tests/testdata/create-busybox-container "$_root" /usr/lib/systemd/tests/testdata/create-busybox-container "$_root"
SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn $SUSE_OPTS--register=no -D "$_root" -b SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" -b
SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn $SUSE_OPTS--register=no -D "$_root" --private-network -b SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" --private-network -b
if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn $SUSE_OPTS--register=no -D "$_root" -U -b; then if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" -U -b; then
[[ "$is_user_ns_supported" = "yes" && "$3" = "network" ]] && return 1 [[ "$is_user_ns_supported" = "yes" && "$3" = "network" ]] && return 1
else else
[[ "$is_user_ns_supported" = "no" && "$3" = "network" ]] && return 1 [[ "$is_user_ns_supported" = "no" && "$3" = "network" ]] && return 1
fi fi
if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn $SUSE_OPTS--register=no -D "$_root" --private-network -U -b; then if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" --private-network -U -b; then
[[ "$is_user_ns_supported" = "yes" && "$3" = "yes" ]] && return 1 [[ "$is_user_ns_supported" = "yes" && "$3" = "yes" ]] && return 1
else else
[[ "$is_user_ns_supported" = "no" && "$3" = "yes" ]] && return 1 [[ "$is_user_ns_supported" = "no" && "$3" = "yes" ]] && return 1
fi fi
local _netns_opt="--network-namespace-path=/proc/self/ns/net" local _netns_opt="--network-namespace-path=/proc/self/ns/net"
local _net_opts=(
"--network-bridge=lo"
"--network-interface=lo"
"--network-ipvlan=lo"
"--network-macvlan=lo"
"--network-veth"
"--network-veth-extra=lo"
"--network-zone=zone"
)
# --network-namespace-path and network-related options cannot be used together # --network-namespace-path and network-related options cannot be used together
if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn $SUSE_OPTS--register=no -D "$_root" "$_netns_opt" --network-interface=lo -b; then for netopt in "${_net_opts[@]}"; do
return 1 echo "$_netns_opt in combination with $netopt should fail"
fi if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" -b "$_netns_opt" "$netopt"; then
echo >&2 "unexpected pass"
if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn $SUSE_OPTS--register=no -D "$_root" "$_netns_opt" --network-macvlan=lo -b; then return 1
return 1 fi
fi done
if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn $SUSE_OPTS--register=no -D "$_root" "$_netns_opt" --network-ipvlan=lo -b; then
return 1
fi
if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn $SUSE_OPTS--register=no -D "$_root" "$_netns_opt" --network-veth -b; then
return 1
fi
if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn $SUSE_OPTS--register=no -D "$_root" "$_netns_opt" --network-veth-extra=lo -b; then
return 1
fi
if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn $SUSE_OPTS--register=no -D "$_root" "$_netns_opt" --network-bridge=lo -b; then
return 1
fi
if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn $SUSE_OPTS--register=no -D "$_root" "$_netns_opt" --network-zone=zone -b; then
return 1
fi
# allow combination of --network-namespace-path and --private-network # allow combination of --network-namespace-path and --private-network
if ! SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn $SUSE_OPTS--register=no -D "$_root" "$_netns_opt" --private-network -b; then if ! SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" -b "$_netns_opt" --private-network; then
return 1 return 1
fi fi
# test --network-namespace-path works with a network namespace created by "ip netns" # test --network-namespace-path works with a network namespace created by "ip netns"
ip netns add nspawn_test ip netns add nspawn_test
_netns_opt="--network-namespace-path=/run/netns/nspawn_test" _netns_opt="--network-namespace-path=/run/netns/nspawn_test"
SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn $SUSE_OPTS--register=no -D "$_root" "$_netns_opt" /bin/ip a | grep -v -E '^1: lo.*UP' SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" "$_netns_opt" /bin/ip a | grep -v -E '^1: lo.*UP'
local r=$? local r=$?
ip netns del nspawn_test ip netns del nspawn_test
if [ $r -ne 0 ]; then if [[ $r -ne 0 ]]; then
return 1 return 1
fi fi

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -eux
set -x set -o pipefail
function setup_root { function setup_root {
local _root="$1" local _root="$1"
@ -21,18 +21,18 @@ r="$(pwd)/overwrite-broken-machine-id"
setup_root "$r" setup_root "$r"
systemd-machine-id-setup --print --root "$r" systemd-machine-id-setup --print --root "$r"
echo abc >>"$r/etc/machine-id" echo abc >>"$r/etc/machine-id"
id=$(systemd-machine-id-setup --print --root "$r") id="$(systemd-machine-id-setup --print --root "$r")"
echo $id >expected echo "$id" >expected
check expected "$r/etc/machine-id" check expected "$r/etc/machine-id"
r="$(pwd)/transient-machine-id" r="$PWD/transient-machine-id"
setup_root "$r" setup_root "$r"
systemd-machine-id-setup --print --root "$r" systemd-machine-id-setup --print --root "$r"
echo abc >>"$r/etc/machine-id" echo abc >>"$r/etc/machine-id"
mount -o remount,ro "$r" mount -o remount,ro "$r"
mount -t tmpfs tmpfs "$r/run" mount -t tmpfs tmpfs "$r/run"
transient_id=$(systemd-machine-id-setup --print --root "$r") transient_id="$(systemd-machine-id-setup --print --root "$r")"
mount -o remount,rw "$r" mount -o remount,rw "$r"
commited_id=$(systemd-machine-id-setup --print --commit --root "$r") commited_id="$(systemd-machine-id-setup --print --commit --root "$r")"
[[ "$transient_id" = "$commited_id" ]] [[ "$transient_id" = "$commited_id" ]]
check "$r/etc/machine-id" "$r/run/machine-id" check "$r/etc/machine-id" "$r/run/machine-id"

View File

@ -1,53 +1,55 @@
#! /bin/bash #!/bin/bash
set -e set -eux
set -x set -o pipefail
_clear_service () { _clear_service () {
systemctl stop $1.service 2>/dev/null || : local SERVICE_NAME="${1:?_clear_service: missing argument}"
rm -f /{etc,run,usr/lib}/systemd/system/$1.service systemctl stop "$SERVICE_NAME.service" 2>/dev/null || :
rm -fr /{etc,run,usr/lib}/systemd/system/$1.service.d rm -f /{etc,run,usr/lib}/systemd/system/"$SERVICE_NAME".service
rm -fr /{etc,run,usr/lib}/systemd/system/$1.service.{wants,requires} rm -fr /{etc,run,usr/lib}/systemd/system/"$SERVICE_NAME".service.d
if [[ $1 == *@ ]]; then rm -fr /{etc,run,usr/lib}/systemd/system/"$SERVICE_NAME".service.{wants,requires}
systemctl stop $1*.service 2>/dev/null || : if [[ $SERVICE_NAME == *@ ]]; then
rm -f /{etc,run,usr/lib}/systemd/system/$1*.service systemctl stop "$SERVICE_NAME"*.service 2>/dev/null || :
rm -fr /{etc,run,usr/lib}/systemd/system/$1*.service.d rm -f /{etc,run,usr/lib}/systemd/system/"$SERVICE_NAME"*.service
rm -fr /{etc,run,usr/lib}/systemd/system/$1*.service.{wants,requires} rm -fr /{etc,run,usr/lib}/systemd/system/"$SERVICE_NAME"*.service.d
rm -fr /{etc,run,usr/lib}/systemd/system/"$SERVICE_NAME"*.service.{wants,requires}
fi fi
} }
clear_services () { clear_services () {
for u in $*; do for u in "$@"; do
_clear_service $u _clear_service "$u"
done done
systemctl daemon-reload systemctl daemon-reload
} }
create_service () { create_service () {
clear_services $1 local SERVICE_NAME="${1:?create_service: missing argument}"
clear_services "$SERVICE_NAME"
cat >/etc/systemd/system/$1.service<<EOF cat >/etc/systemd/system/"$SERVICE_NAME".service <<EOF
[Unit] [Unit]
Description=$1 unit Description=$SERVICE_NAME unit
[Service] [Service]
ExecStart=/bin/sleep 100000 ExecStart=/bin/sleep 100000
EOF EOF
mkdir -p /{etc,run,usr/lib}/systemd/system/$1.service.d mkdir -p /{etc,run,usr/lib}/systemd/system/"$SERVICE_NAME".service.d
mkdir -p /etc/systemd/system/$1.service.{wants,requires} mkdir -p /etc/systemd/system/"$SERVICE_NAME".service.{wants,requires}
mkdir -p /run/systemd/system/$1.service.{wants,requires} mkdir -p /run/systemd/system/"$SERVICE_NAME".service.{wants,requires}
mkdir -p /usr/lib/systemd/system/$1.service.{wants,requires} mkdir -p /usr/lib/systemd/system/"$SERVICE_NAME".service.{wants,requires}
} }
create_services () { create_services () {
for u in $*; do for u in "$@"; do
create_service $u create_service "$u"
done done
} }
check_ok () { check_ok () {
[ $# -eq 3 ] || return [ $# -eq 3 ] || return
x="$(systemctl show --value -p $2 $1)" x="$(systemctl show --value -p "$2" "$1")"
case "$x" in case "$x" in
*$3*) return 0 ;; *$3*) return 0 ;;
*) return 1 ;; *) return 1 ;;

View File

@ -1,25 +1,24 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -v -x set -eux
set -o pipefail
rm -f /test.log rm -f /test.log
TL=/test.log.XXXXXXXX TESTLOG=/test.log.XXXXXXXX
function wait_for() function wait_for()
{ {
service=${1} local service="${1:-wait_for: missing service argument}"
result=${2:-success} local result="${2:-success}"
time=${3:-45} local time="${3:-45}"
while [[ ! -f /${service}.terminated && ! -f /${service}.success && $time -gt 0 ]] while [[ ! -f /${service}.terminated && ! -f /${service}.success && $time -gt 0 ]]; do
do
sleep 1 sleep 1
time=$(( $time - 1 )) time=$((time - 1))
done done
if [[ ! -f /${service}.${result} ]] if [[ ! -f /${service}.${result} ]]; then
then journalctl -u "${service/_/-}.service" >>"$TESTLOG"
journalctl -u ${service/_/-}.service >> "${TL}"
fi fi
} }
@ -44,12 +43,11 @@ wait_for fail_start startfail
wait_for fail_stop stopfail wait_for fail_stop stopfail
wait_for fail_runtime runtimefail wait_for fail_runtime runtimefail
if [[ -f "${TL}" ]] if [[ -f "$TESTLOG" ]]; then
then
# no mv # no mv
cp "${TL}" /test.log cp "$TESTLOG" /test.log
exit 1 exit 1
else
touch /testok
exit 0
fi fi
touch /testok
exit 0

View File

@ -27,7 +27,7 @@ run_test() {
echo add >/sys/class/net/lo/uevent echo add >/sys/class/net/lo/uevent
for n in {1..20}; do for _ in {1..20}; do
sleep 5 sleep 5
if coredumpctl --since "$since" --no-legend --no-pager | grep /bin/udevadm ; then if coredumpctl --since "$since" --no-legend --no-pager | grep /bin/udevadm ; then
return 0 return 0

View File

@ -1,12 +1,12 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -x set -eux
set -e set -o pipefail
>/failed : >/failed
for t in ${0%.sh}.*.sh; do for t in "${0%.sh}".*.sh; do
echo "Running $t"; ./$t echo "Running $t"; ./"$t"
done done
touch /testok touch /testok

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
systemd-run --wait -p FailureAction=poweroff true systemd-run --wait -p FailureAction=poweroff true

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
if grep -q cgroup2 /proc/filesystems ; then if grep -q cgroup2 /proc/filesystems ; then

View File

@ -1,11 +1,11 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
systemd-analyze log-level debug systemd-analyze log-level debug
systemd-analyze log-target console systemd-analyze log-target console
test `systemctl show -P MainPID testsuite-20.service` -eq $$ test "$(systemctl show -P MainPID testsuite-20.service)" -eq $$
# Start a test process inside of our own cgroup # Start a test process inside of our own cgroup
sleep infinity & sleep infinity &
@ -14,45 +14,45 @@ disown
# Start a test process outside of our own cgroup # Start a test process outside of our own cgroup
systemd-run -p DynamicUser=1 --unit=test20-sleep.service /bin/sleep infinity systemd-run -p DynamicUser=1 --unit=test20-sleep.service /bin/sleep infinity
EXTERNALPID=`systemctl show -P MainPID test20-sleep.service` EXTERNALPID="$(systemctl show -P MainPID test20-sleep.service)"
# Update our own main PID to the external test PID, this should work # Update our own main PID to the external test PID, this should work
systemd-notify MAINPID=$EXTERNALPID systemd-notify MAINPID="$EXTERNALPID"
test `systemctl show -P MainPID testsuite-20.service` -eq $EXTERNALPID test "$(systemctl show -P MainPID testsuite-20.service)" -eq "$EXTERNALPID"
# Update our own main PID to the internal test PID, this should work, too # Update our own main PID to the internal test PID, this should work, too
systemd-notify MAINPID=$INTERNALPID systemd-notify MAINPID=$INTERNALPID
test `systemctl show -P MainPID testsuite-20.service` -eq $INTERNALPID test "$(systemctl show -P MainPID testsuite-20.service)" -eq "$INTERNALPID"
# Update it back to our own PID, this should also work # Update it back to our own PID, this should also work
systemd-notify MAINPID=$$ systemd-notify MAINPID=$$
test `systemctl show -P MainPID testsuite-20.service` -eq $$ test "$(systemctl show -P MainPID testsuite-20.service)" -eq $$
# Try to set it to PID 1, which it should ignore, because that's the manager # Try to set it to PID 1, which it should ignore, because that's the manager
systemd-notify MAINPID=1 systemd-notify MAINPID=1
test `systemctl show -P MainPID testsuite-20.service` -eq $$ test "$(systemctl show -P MainPID testsuite-20.service)" -eq $$
# Try to set it to PID 0, which is invalid and should be ignored # Try to set it to PID 0, which is invalid and should be ignored
systemd-notify MAINPID=0 systemd-notify MAINPID=0
test `systemctl show -P MainPID testsuite-20.service` -eq $$ test "$(systemctl show -P MainPID testsuite-20.service)" -eq $$
# Try to set it to a valid but non-existing PID, which should be ignored. (Note # Try to set it to a valid but non-existing PID, which should be ignored. (Note
# that we set the PID to a value well above any known /proc/sys/kernel/pid_max, # that we set the PID to a value well above any known /proc/sys/kernel/pid_max,
# which means we can be pretty sure it doesn't exist by coincidence) # which means we can be pretty sure it doesn't exist by coincidence)
systemd-notify MAINPID=1073741824 systemd-notify MAINPID=1073741824
test `systemctl show -P MainPID testsuite-20.service` -eq $$ test "$(systemctl show -P MainPID testsuite-20.service)" -eq $$
# Change it again to the external PID, without privileges this time. This should be ignored, because the PID is from outside of our cgroup and we lack privileges. # Change it again to the external PID, without privileges this time. This should be ignored, because the PID is from outside of our cgroup and we lack privileges.
systemd-notify --uid=1000 MAINPID=$EXTERNALPID systemd-notify --uid=1000 MAINPID="$EXTERNALPID"
test `systemctl show -P MainPID testsuite-20.service` -eq $$ test "$(systemctl show -P MainPID testsuite-20.service)" -eq $$
# Change it again to the internal PID, without privileges this time. This should work, as the process is on our cgroup, and that's enough even if we lack privileges. # Change it again to the internal PID, without privileges this time. This should work, as the process is on our cgroup, and that's enough even if we lack privileges.
systemd-notify --uid=1000 MAINPID=$INTERNALPID systemd-notify --uid=1000 MAINPID="$INTERNALPID"
test `systemctl show -P MainPID testsuite-20.service` -eq $INTERNALPID test "$(systemctl show -P MainPID testsuite-20.service)" -eq "$INTERNALPID"
# Update it back to our own PID, this should also work # Update it back to our own PID, this should also work
systemd-notify --uid=1000 MAINPID=$$ systemd-notify --uid=1000 MAINPID=$$
test `systemctl show -P MainPID testsuite-20.service` -eq $$ test "$(systemctl show -P MainPID testsuite-20.service)" -eq $$
cat >/tmp/test20-mainpid.sh <<EOF cat >/tmp/test20-mainpid.sh <<EOF
#!/usr/bin/env bash #!/usr/bin/env bash
@ -76,7 +76,7 @@ EOF
chmod +x /tmp/test20-mainpid.sh chmod +x /tmp/test20-mainpid.sh
systemd-run --unit=test20-mainpidsh.service -p StandardOutput=tty -p StandardError=tty -p Type=forking -p RuntimeDirectory=mainpidsh -p PIDFile=/run/mainpidsh/pid /tmp/test20-mainpid.sh systemd-run --unit=test20-mainpidsh.service -p StandardOutput=tty -p StandardError=tty -p Type=forking -p RuntimeDirectory=mainpidsh -p PIDFile=/run/mainpidsh/pid /tmp/test20-mainpid.sh
test `systemctl show -P MainPID test20-mainpidsh.service` -eq `cat /run/mainpidsh/pid` test "$(systemctl show -P MainPID test20-mainpidsh.service)" -eq "$(cat /run/mainpidsh/pid)"
cat >/tmp/test20-mainpid2.sh <<EOF cat >/tmp/test20-mainpid2.sh <<EOF
#!/usr/bin/env bash #!/usr/bin/env bash
@ -101,7 +101,7 @@ EOF
chmod +x /tmp/test20-mainpid2.sh chmod +x /tmp/test20-mainpid2.sh
systemd-run --unit=test20-mainpidsh2.service -p StandardOutput=tty -p StandardError=tty -p Type=forking -p RuntimeDirectory=mainpidsh2 -p PIDFile=/run/mainpidsh2/pid /tmp/test20-mainpid2.sh systemd-run --unit=test20-mainpidsh2.service -p StandardOutput=tty -p StandardError=tty -p Type=forking -p RuntimeDirectory=mainpidsh2 -p PIDFile=/run/mainpidsh2/pid /tmp/test20-mainpid2.sh
test `systemctl show -P MainPID test20-mainpidsh2.service` -eq `cat /run/mainpidsh2/pid` test "$(systemctl show -P MainPID test20-mainpidsh2.service)" -eq "$(cat /run/mainpidsh2/pid)"
cat >/dev/shm/test20-mainpid3.sh <<EOF cat >/dev/shm/test20-mainpid3.sh <<EOF
#!/usr/bin/env bash #!/usr/bin/env bash
@ -140,7 +140,7 @@ systemd-run --unit=test20-mainpidsh3.service \
&& { echo 'unexpected success'; exit 1; } && { echo 'unexpected success'; exit 1; }
# Test that this failed due to timeout, and not some other error # Test that this failed due to timeout, and not some other error
test $(systemctl show -P Result test20-mainpidsh3.service) = timeout test "$(systemctl show -P Result test20-mainpidsh3.service)" = timeout
systemd-analyze log-level info systemd-analyze log-level info

View File

@ -1,10 +1,11 @@
#! /bin/bash #!/bin/bash
# #
# With "e" don't attempt to set permissions when file doesn't exist, see # With "e" don't attempt to set permissions when file doesn't exist, see
# https://github.com/systemd/systemd/pull/6682. # https://github.com/systemd/systemd/pull/6682.
# #
set -e set -eux
set -o pipefail
rm -fr /tmp/test rm -fr /tmp/test

View File

@ -1,10 +1,10 @@
#! /bin/bash #!/bin/bash
# #
# Basic tests for types creating directories # Basic tests for types creating directories
# #
set -e set -eux
set -x set -o pipefail
rm -fr /tmp/{C,d,D,e} rm -fr /tmp/{C,d,D,e}
mkdir /tmp/{C,d,D,e} mkdir /tmp/{C,d,D,e}
@ -21,10 +21,10 @@ d /tmp/d/2 0755 daemon daemon - -
EOF EOF
test -d /tmp/d/1 test -d /tmp/d/1
test $(stat -c %U:%G:%a /tmp/d/1) = "daemon:daemon:755" test "$(stat -c %U:%G:%a /tmp/d/1)" = "daemon:daemon:755"
test -d /tmp/d/2 test -d /tmp/d/2
test $(stat -c %U:%G:%a /tmp/d/2) = "daemon:daemon:755" test "$(stat -c %U:%G:%a /tmp/d/2)" = "daemon:daemon:755"
# #
# 'D' # 'D'
@ -39,10 +39,10 @@ D /tmp/D/2 0755 daemon daemon - -
EOF EOF
test -d /tmp/D/1 test -d /tmp/D/1
test $(stat -c %U:%G:%a /tmp/D/1) = "daemon:daemon:755" test "$(stat -c %U:%G:%a /tmp/D/1)" = "daemon:daemon:755"
test -d /tmp/D/2 test -d /tmp/D/2
test $(stat -c %U:%G:%a /tmp/D/2) = "daemon:daemon:755" test "$(stat -c %U:%G:%a /tmp/D/2)" = "daemon:daemon:755"
systemd-tmpfiles --remove - <<EOF systemd-tmpfiles --remove - <<EOF
D /tmp/D/2 0755 daemon daemon - - D /tmp/D/2 0755 daemon daemon - -
@ -66,12 +66,12 @@ EOF
test ! -d /tmp/e/1 test ! -d /tmp/e/1
test -d /tmp/e/2 test -d /tmp/e/2
test $(stat -c %U:%G:%a /tmp/e/2) = "root:root:777" test "$(stat -c %U:%G:%a /tmp/e/2)" = "root:root:777"
test -d /tmp/e/2/d1 test -d /tmp/e/2/d1
test $(stat -c %U:%G:%a /tmp/e/2/d1) = "daemon:daemon:755" test "$(stat -c %U:%G:%a /tmp/e/2/d1)" = "daemon:daemon:755"
test -d /tmp/e/2/d2 test -d /tmp/e/2/d2
test $(stat -c %U:%G:%a /tmp/e/2/d2) = "daemon:daemon:755" test "$(stat -c %U:%G:%a /tmp/e/2/d2)" = "daemon:daemon:755"
# 'e' operates on directories only # 'e' operates on directories only
mkdir -p /tmp/e/3/{d1,d2} mkdir -p /tmp/e/3/{d1,d2}
@ -87,12 +87,12 @@ EOF
# the directories should have been processed although systemd-tmpfiles failed # the directories should have been processed although systemd-tmpfiles failed
# previously due to the presence of a file. # previously due to the presence of a file.
test -d /tmp/e/3/d1 test -d /tmp/e/3/d1
test $(stat -c %U:%G:%a /tmp/e/3/d1) = "daemon:daemon:755" test "$(stat -c %U:%G:%a /tmp/e/3/d1)" = "daemon:daemon:755"
test -d /tmp/e/3/d2 test -d /tmp/e/3/d2
test $(stat -c %U:%G:%a /tmp/e/3/d2) = "daemon:daemon:755" test "$(stat -c %U:%G:%a /tmp/e/3/d2)" = "daemon:daemon:755"
test -f /tmp/e/3/f1 test -f /tmp/e/3/f1
test $(stat -c %U:%G:%a /tmp/e/3/f1) = "root:root:644" test "$(stat -c %U:%G:%a /tmp/e/3/f1)" = "root:root:644"
# #
# 'C' # 'C'
@ -111,12 +111,12 @@ C /tmp/C/2 0755 daemon daemon - /tmp/C/2-origin
EOF EOF
test -d /tmp/C/1 test -d /tmp/C/1
test $(stat -c %U:%G:%a /tmp/C/1/f1) = "daemon:daemon:755" test "$(stat -c %U:%G:%a /tmp/C/1/f1)" = "daemon:daemon:755"
test -d /tmp/C/2 test -d /tmp/C/2
test $(stat -c %U:%G:%a /tmp/C/2/f1) = "daemon:daemon:755" test "$(stat -c %U:%G:%a /tmp/C/2/f1)" = "daemon:daemon:755"
systemd-tmpfiles --create - <<EOF systemd-tmpfiles --create - <<EOF
C /tmp/C/3 0755 daemon daemon - /tmp/C/3-origin C /tmp/C/3 0755 daemon daemon - /tmp/C/3-origin
EOF EOF
test $(stat -c %U:%G:%a /tmp/C/3/f1) = "root:root:644" test "$(stat -c %U:%G:%a /tmp/C/3/f1)" = "root:root:644"

View File

@ -1,10 +1,10 @@
#! /bin/bash #!/bin/bash
# #
# Basic tests for types creating/writing files # Basic tests for types creating/writing files
# #
set -e set -eux
set -x set -o pipefail
rm -fr /tmp/{f,F,w} rm -fr /tmp/{f,F,w}
mkdir /tmp/{f,F,w} mkdir /tmp/{f,F,w}
@ -20,9 +20,9 @@ EOF
### '1' should exist and be empty ### '1' should exist and be empty
test -f /tmp/f/1; test ! -s /tmp/f/1 test -f /tmp/f/1; test ! -s /tmp/f/1
test $(stat -c %U:%G:%a /tmp/f/1) = "root:root:644" test "$(stat -c %U:%G:%a /tmp/f/1)" = "root:root:644"
test $(stat -c %U:%G:%a /tmp/f/2) = "root:root:644" test "$(stat -c %U:%G:%a /tmp/f/2)" = "root:root:644"
test "$(< /tmp/f/2)" = "This string should be written" test "$(< /tmp/f/2)" = "This string should be written"
### The perms are supposed to be updated even if the file already exists. ### The perms are supposed to be updated even if the file already exists.
@ -32,7 +32,7 @@ EOF
# file should be empty # file should be empty
test ! -s /tmp/f/1 test ! -s /tmp/f/1
test $(stat -c %U:%G:%a /tmp/f/1) = "daemon:daemon:666" test "$(stat -c %U:%G:%a /tmp/f/1)" = "daemon:daemon:666"
### But we shouldn't try to set perms on an existing file which is not a ### But we shouldn't try to set perms on an existing file which is not a
### regular one. ### regular one.
@ -44,7 +44,7 @@ f /tmp/f/fifo 0666 daemon daemon - This string should not be written
EOF EOF
test -p /tmp/f/fifo test -p /tmp/f/fifo
test $(stat -c %U:%G:%a /tmp/f/fifo) = "root:root:644" test "$(stat -c %U:%G:%a /tmp/f/fifo)" = "root:root:644"
### 'f' should not follow symlinks. ### 'f' should not follow symlinks.
ln -s missing /tmp/f/dangling ln -s missing /tmp/f/dangling
@ -55,7 +55,7 @@ f /tmp/f/dangling 0644 daemon daemon - -
f /tmp/f/symlink 0644 daemon daemon - - f /tmp/f/symlink 0644 daemon daemon - -
EOF EOF
test ! -e /tmp/f/missing test ! -e /tmp/f/missing
test $(stat -c %U:%G:%a /tmp/file-owned-by-root) = "root:root:644" test "$(stat -c %U:%G:%a /tmp/file-owned-by-root)" = "root:root:644"
### Handle read-only filesystem gracefully: we shouldn't fail if the target ### Handle read-only filesystem gracefully: we shouldn't fail if the target
### already exists and have the correct perms. ### already exists and have the correct perms.
@ -75,7 +75,7 @@ test -f /tmp/f/ro-fs/foo; test ! -s /tmp/f/ro-fs/foo
systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; } systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }
f /tmp/f/ro-fs/foo 0666 - - - - f /tmp/f/ro-fs/foo 0666 - - - -
EOF EOF
test $(stat -c %U:%G:%a /tmp/f/fifo) = "root:root:644" test "$(stat -c %U:%G:%a /tmp/f/fifo)" = "root:root:644"
systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; } systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }
f /tmp/f/ro-fs/bar 0644 - - - - f /tmp/f/ro-fs/bar 0644 - - - -
@ -109,9 +109,9 @@ test -f /tmp/F/created; test ! -s /tmp/F/created
test -f /tmp/F/created-with-content test -f /tmp/F/created-with-content
test "$(< /tmp/F/created-with-content)" = "new content" test "$(< /tmp/F/created-with-content)" = "new content"
test -f /tmp/F/truncated; test ! -s /tmp/F/truncated test -f /tmp/F/truncated; test ! -s /tmp/F/truncated
test $(stat -c %U:%G:%a /tmp/F/truncated) = "daemon:daemon:666" test "$(stat -c %U:%G:%a /tmp/F/truncated)" = "daemon:daemon:666"
test -s /tmp/F/truncated-with-content test -s /tmp/F/truncated-with-content
test $(stat -c %U:%G:%a /tmp/F/truncated-with-content) = "daemon:daemon:666" test "$(stat -c %U:%G:%a /tmp/F/truncated-with-content)" = "daemon:daemon:666"
### We shouldn't try to truncate anything but regular files since the behavior is ### We shouldn't try to truncate anything but regular files since the behavior is
### unspecified in the other cases. ### unspecified in the other cases.
@ -132,7 +132,7 @@ f /tmp/F/dangling 0644 daemon daemon - -
f /tmp/F/symlink 0644 daemon daemon - - f /tmp/F/symlink 0644 daemon daemon - -
EOF EOF
test ! -e /tmp/F/missing test ! -e /tmp/F/missing
test $(stat -c %U:%G:%a /tmp/file-owned-by-root) = "root:root:644" test "$(stat -c %U:%G:%a /tmp/file-owned-by-root)" = "root:root:644"
### Handle read-only filesystem gracefully: we shouldn't fail if the target ### Handle read-only filesystem gracefully: we shouldn't fail if the target
### already exists and is empty. ### already exists and is empty.
@ -161,11 +161,11 @@ test -f /tmp/F/ro-fs/foo
grep -q 'truncating is not allowed' /tmp/F/ro-fs/foo grep -q 'truncating is not allowed' /tmp/F/ro-fs/foo
# Trying to change the perms should fail. # Trying to change the perms should fail.
>/tmp/F/rw-fs/foo : >/tmp/F/rw-fs/foo
systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; } systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }
F /tmp/F/ro-fs/foo 0666 - - - - F /tmp/F/ro-fs/foo 0666 - - - -
EOF EOF
test $(stat -c %U:%G:%a /tmp/F/ro-fs/foo) = "root:root:644" test "$(stat -c %U:%G:%a /tmp/F/ro-fs/foo)" = "root:root:644"
### Try to create a new file. ### Try to create a new file.
systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; } systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }

View File

@ -1,10 +1,10 @@
#! /bin/bash #!/bin/bash
# #
# Basic tests for types creating fifos # Basic tests for types creating fifos
# #
set -e set -eux
set -x set -o pipefail
rm -fr /tmp/p rm -fr /tmp/p
mkdir /tmp/p mkdir /tmp/p
@ -15,7 +15,7 @@ p /tmp/p/fifo1 0666 - - - -
EOF EOF
test -p /tmp/p/fifo1 test -p /tmp/p/fifo1
test $(stat -c %U:%G:%a /tmp/p/fifo1) = "root:root:666" test "$(stat -c %U:%G:%a /tmp/p/fifo1)" = "root:root:666"
# Refuse to overwrite an existing file. Error is not propagated. # Refuse to overwrite an existing file. Error is not propagated.
systemd-tmpfiles --create - <<EOF systemd-tmpfiles --create - <<EOF
@ -30,7 +30,7 @@ p+ /tmp/p/f1 0666 - - - -
EOF EOF
test -p /tmp/p/f1 test -p /tmp/p/f1
test $(stat -c %U:%G:%a /tmp/p/f1) = "root:root:666" test "$(stat -c %U:%G:%a /tmp/p/f1)" = "root:root:666"
# #
# Must be fixed # Must be fixed

View File

@ -1,7 +1,7 @@
#! /bin/bash #! /bin/bash
set -e set -eux
set -x set -o pipefail
rm -fr /tmp/{z,Z} rm -fr /tmp/{z,Z}
mkdir /tmp/{z,Z} mkdir /tmp/{z,Z}
@ -17,15 +17,15 @@ z /tmp/z/f1 0755 daemon daemon - -
z /tmp/z/d1 0755 daemon daemon - - z /tmp/z/d1 0755 daemon daemon - -
EOF EOF
test $(stat -c %U:%G /tmp/z/f1) = "daemon:daemon" test "$(stat -c %U:%G /tmp/z/f1)" = "daemon:daemon"
test $(stat -c %U:%G /tmp/z/d1) = "daemon:daemon" test "$(stat -c %U:%G /tmp/z/d1)" = "daemon:daemon"
test $(stat -c %U:%G /tmp/z/d1/f11) = "root:root" test "$(stat -c %U:%G /tmp/z/d1/f11)" = "root:root"
systemd-tmpfiles --create - <<EOF systemd-tmpfiles --create - <<EOF
z /tmp/z/d2/* 0755 daemon daemon - - z /tmp/z/d2/* 0755 daemon daemon - -
EOF EOF
test $(stat -c %U:%G /tmp/z/d2/f21) = "daemon:daemon" test "$(stat -c %U:%G /tmp/z/d2/f21)" = "daemon:daemon"
# #
# 'Z' # 'Z'
@ -38,8 +38,8 @@ Z /tmp/Z/f1 0755 daemon daemon - -
Z /tmp/Z/d1 0755 daemon daemon - - Z /tmp/Z/d1 0755 daemon daemon - -
EOF EOF
test $(stat -c %U:%G /tmp/Z/f1) = "daemon:daemon" test "$(stat -c %U:%G /tmp/Z/f1)" = "daemon:daemon"
test $(stat -c %U:%G /tmp/Z/d1) = "daemon:daemon" test "$(stat -c %U:%G /tmp/Z/d1)" = "daemon:daemon"
test $(stat -c %U:%G /tmp/Z/d1/d11) = "daemon:daemon" test "$(stat -c %U:%G /tmp/Z/d1/d11)" = "daemon:daemon"
test $(stat -c %U:%G /tmp/Z/d1/f11) = "daemon:daemon" test "$(stat -c %U:%G /tmp/Z/d1/f11)" = "daemon:daemon"
test $(stat -c %U:%G /tmp/Z/d1/d11/f111) = "daemon:daemon" test "$(stat -c %U:%G /tmp/Z/d1/d11/f111)" = "daemon:daemon"

View File

@ -1,9 +1,10 @@
#! /bin/bash #!/bin/bash
# #
# Inspired by https://github.com/systemd/systemd/issues/9508 # Inspired by https://github.com/systemd/systemd/issues/9508
# #
set -e set -eux
set -o pipefail
test_snippet() { test_snippet() {
systemd-tmpfiles "$@" - <<EOF systemd-tmpfiles "$@" - <<EOF

View File

@ -1,10 +1,10 @@
#! /bin/bash #!/bin/bash
# #
# Verifies the issues described by https://github.com/systemd/systemd/issues/10191 # Verifies the issues described by https://github.com/systemd/systemd/issues/10191
# #
set -e set -eux
set -x set -o pipefail
rm -rf /tmp/test-prefix rm -rf /tmp/test-prefix

View File

@ -1,4 +1,4 @@
#! /bin/bash #!/bin/bash
# #
# Verify tmpfiles can run in a root directory under a path prefix that contains # Verify tmpfiles can run in a root directory under a path prefix that contains
# directories owned by unprivileged users, for example when a root file system # directories owned by unprivileged users, for example when a root file system
@ -7,7 +7,8 @@
# https://github.com/systemd/systemd/pull/11820 # https://github.com/systemd/systemd/pull/11820
# #
set -e set -eux
set -o pipefail
rm -fr /tmp/root /tmp/user rm -fr /tmp/root /tmp/user
mkdir -p /tmp/root /tmp/user/root mkdir -p /tmp/root /tmp/user/root

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -eux
set -x set -o pipefail
# Make sure that the "stat" output is not locale dependent. # Make sure that the "stat" output is not locale dependent.
export LANG=C LC_ALL=C export LANG=C LC_ALL=C

View File

@ -1,7 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -eux
set -x
set -o pipefail set -o pipefail
systemd-tmpfiles --create - <<EOF systemd-tmpfiles --create - <<EOF

View File

@ -1,12 +1,12 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -x set -eux
set -e set -o pipefail
>/failed : >/failed
for t in ${0%.sh}.*.sh; do for t in "${0%.sh}".*.sh; do
echo "Running $t"; ./$t echo "Running $t"; ./"$t"
done done
touch /testok touch /testok

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
systemd-analyze log-level debug systemd-analyze log-level debug
@ -21,8 +21,8 @@ systemd-run --unit=six -p Type=exec /tmp/brokenbinary && { echo 'unexpected succ
systemd-run --unit=seven -p KillSignal=SIGTERM -p RestartKillSignal=SIGINT -p Type=exec /bin/sleep infinity systemd-run --unit=seven -p KillSignal=SIGTERM -p RestartKillSignal=SIGINT -p Type=exec /bin/sleep infinity
# Both TERM and SIGINT happen to have the same number on all architectures # Both TERM and SIGINT happen to have the same number on all architectures
test $(systemctl show --value -p KillSignal seven.service) -eq 15 test "$(systemctl show --value -p KillSignal seven.service)" -eq 15
test $(systemctl show --value -p RestartKillSignal seven.service) -eq 2 test "$(systemctl show --value -p RestartKillSignal seven.service)" -eq 2
systemctl restart seven.service systemctl restart seven.service
systemctl stop seven.service systemctl stop seven.service

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
export SYSTEMD_PAGER=cat export SYSTEMD_PAGER=cat
@ -120,6 +120,7 @@ test ! -f /var/lib/machines/scratch4
machinectl image-status scratch4 && { echo 'unexpected success'; exit 1; } machinectl image-status scratch4 && { echo 'unexpected success'; exit 1; }
# Test import-tar hyphen/stdin pipe behavior # Test import-tar hyphen/stdin pipe behavior
# shellcheck disable=SC2002
cat /var/tmp/scratch.tar.gz | machinectl import-tar - scratch5 cat /var/tmp/scratch.tar.gz | machinectl import-tar - scratch5
test -d /var/lib/machines/scratch5 test -d /var/lib/machines/scratch5
machinectl image-status scratch5 machinectl image-status scratch5

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
# Make sure PATH is set # Make sure PATH is set

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
systemd-analyze log-level debug systemd-analyze log-level debug

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 sts=4 et filetype=sh # ex: ts=8 sw=4 sts=4 et filetype=sh
set -ex set -eux
set -o pipefail set -o pipefail
export SYSTEMD_LOG_LEVEL=debug export SYSTEMD_LOG_LEVEL=debug

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
systemd-analyze log-level debug systemd-analyze log-level debug

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -eux
set -o pipefail set -o pipefail
if journalctl -b -t systemd --grep '\.device: Changed plugged -> dead'; then if journalctl -b -t systemd --grep '\.device: Changed plugged -> dead'; then

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
# Let's run this test only if the "memory.oom.group" cgroupfs attribute # Let's run this test only if the "memory.oom.group" cgroupfs attribute
@ -9,7 +9,6 @@ set -o pipefail
# kernels where the concept was still new. # kernels where the concept was still new.
if test -f /sys/fs/cgroup/system.slice/testsuite-32.service/memory.oom.group; then if test -f /sys/fs/cgroup/system.slice/testsuite-32.service/memory.oom.group; then
systemd-analyze log-level debug systemd-analyze log-level debug
systemd-analyze log-target console systemd-analyze log-target console
@ -23,12 +22,12 @@ if test -f /sys/fs/cgroup/system.slice/testsuite-32.service/memory.oom.group; th
echo f >/proc/sysrq-trigger echo f >/proc/sysrq-trigger
while : ; do while : ; do
STATE=`systemctl show -P ActiveState oomtest.service` STATE="$(systemctl show -P ActiveState oomtest.service)"
[ "$STATE" = "failed" ] && break [ "$STATE" = "failed" ] && break
sleep .5 sleep .5
done done
RESULT=`systemctl show -P Result oomtest.service` RESULT="$(systemctl show -P Result oomtest.service)"
test "$RESULT" = "oom-kill" test "$RESULT" = "oom-kill"
systemd-analyze log-level info systemd-analyze log-level info

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 sts=4 et filetype=sh # ex: ts=8 sw=4 sts=4 et filetype=sh
set -ex set -eux
set -o pipefail set -o pipefail
cat >/etc/systemd/system/testservice.service <<EOF cat >/etc/systemd/system/testservice.service <<EOF

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
systemd-analyze log-level debug systemd-analyze log-level debug

View File

@ -1,13 +1,14 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
at_exit() { at_exit() {
if [ $? -ne 0 ]; then # shellcheck disable=SC2181
if [[ $? -ne 0 ]]; then
# We're exiting with a non-zero EC, let's dump test artifacts # We're exiting with a non-zero EC, let's dump test artifacts
# for easier debugging # for easier debugging
[ -f "$straceLog" ] && cat "$straceLog" [[ -v straceLog && -f "$straceLog" ]] && cat "$straceLog"
[ -f "$journalLog" ] && cat "$journalLog" [[ -v journalLog && -f "$journalLog" ]] && cat "$journalLog"
fi fi
} }
@ -26,25 +27,28 @@ testUnitFile="/run/systemd/system/$testUnit"
testUnitNUMAConf="$testUnitFile.d/numa.conf" testUnitNUMAConf="$testUnitFile.d/numa.conf"
# Sleep constants (we should probably figure out something better but nothing comes to mind) # Sleep constants (we should probably figure out something better but nothing comes to mind)
journalSleep=5
sleepAfterStart=1 sleepAfterStart=1
# Journal cursor for easier navigation # Journal cursor for easier navigation
journalCursorFile="jounalCursorFile" journalCursorFile="jounalCursorFile"
startStrace() { startStrace() {
coproc strace -qq -p 1 -o $straceLog -e set_mempolicy -s 1024 $1 coproc strace -qq -p 1 -o "$straceLog" -e set_mempolicy -s 1024 ${1:+"$1"}
# Wait for strace to properly "initialize" # Wait for strace to properly "initialize"
sleep $sleepAfterStart sleep $sleepAfterStart
} }
stopStrace() { stopStrace() {
kill -s TERM $COPROC_PID [[ -v COPROC_PID ]] || return
local PID=$COPROC_PID
kill -s TERM "$PID"
# Make sure the strace process is indeed dead # Make sure the strace process is indeed dead
while kill -0 $COPROC_PID 2>/dev/null; do sleep 0.1; done while kill -0 "$PID" 2>/dev/null; do sleep 0.1; done
} }
startJournalctl() { startJournalctl() {
: >"$journalCursorFile"
# Save journal's cursor for later navigation # Save journal's cursor for later navigation
journalctl --no-pager --cursor-file="$journalCursorFile" -n0 -ocat journalctl --no-pager --cursor-file="$journalCursorFile" -n0 -ocat
} }
@ -55,7 +59,7 @@ stopJournalctl() {
# the --sync wait until the synchronization is complete # the --sync wait until the synchronization is complete
echo "Force journald to write all queued messages" echo "Force journald to write all queued messages"
journalctl --sync journalctl --sync
journalctl -u $unit --cursor-file="$journalCursorFile" >"$journalLog" journalctl -u "$unit" --cursor-file="$journalCursorFile" >"$journalLog"
} }
checkNUMA() { checkNUMA() {
@ -64,21 +68,24 @@ checkNUMA() {
} }
writePID1NUMAPolicy() { writePID1NUMAPolicy() {
echo [Manager] >$confDir/numa.conf cat >"$confDir/numa.conf" <<EOF
echo NUMAPolicy=$1 >>$confDir/numa.conf [Manager]
echo NUMAMask=$2 >>$confDir/numa.conf NUMAPolicy=${1:?missing argument: NUMAPolicy}
NUMAMask=${2:-""}
EOF
} }
writeTestUnit() { writeTestUnit() {
mkdir -p $testUnitFile.d/ mkdir -p "$testUnitFile.d/"
echo [Service] >$testUnitFile printf "[Service]\nExecStart=/bin/sleep 3600\n" >"$testUnitFile"
echo ExecStart=/bin/sleep 3600 >>$testUnitFile
} }
writeTestUnitNUMAPolicy() { writeTestUnitNUMAPolicy() {
echo [Service] >$testUnitNUMAConf cat >"$testUnitNUMAConf" <<EOF
echo NUMAPolicy=$1 >>$testUnitNUMAConf [Service]
echo NUMAMask=$2 >>$testUnitNUMAConf NUMAPolicy=${1:?missing argument: NUMAPolicy}
NUMAMask=${2:-""}
EOF
systemctl daemon-reload systemctl daemon-reload
} }
@ -97,32 +104,38 @@ pid1ReloadWithJournal() {
pid1StartUnitWithStrace() { pid1StartUnitWithStrace() {
startStrace '-f' startStrace '-f'
systemctl start $1 systemctl start "${1:?missing unit name}"
sleep $sleepAfterStart sleep $sleepAfterStart
stopStrace stopStrace
} }
pid1StartUnitWithJournal() { pid1StartUnitWithJournal() {
startJournalctl startJournalctl
systemctl start $1 systemctl start "${1:?missing unit name}"
sleep $sleepAfterStart sleep $sleepAfterStart
stopJournalctl stopJournalctl
} }
pid1StopUnit() { pid1StopUnit() {
systemctl stop $1 systemctl stop "${1:?missing unit name}"
} }
systemctlCheckNUMAProperties() { systemctlCheckNUMAProperties() {
local LOGFILE="$(mktemp)" local UNIT_NAME="${1:?missing unit name}"
systemctl show -p NUMAPolicy $1 >"$LOGFILE" local NUMA_POLICY="${2:?missing NUMAPolicy}"
grep "NUMAPolicy=$2" "$LOGFILE" local NUMA_MASK="${3:-""}"
local LOGFILE
>"$LOGFILE" LOGFILE="$(mktemp)"
if [ -n "$3" ]; then systemctl show -p NUMAPolicy "$UNIT_NAME" >"$LOGFILE"
systemctl show -p NUMAMask $1 >"$LOGFILE" grep "NUMAPolicy=$NUMA_POLICY" "$LOGFILE"
grep "NUMAMask=$3" "$LOGFILE"
: >"$LOGFILE"
if [ -n "$NUMA_MASK" ]; then
systemctl show -p NUMAMask "$UNIT_NAME" >"$LOGFILE"
grep "NUMAMask=$NUMA_MASK" "$LOGFILE"
fi fi
} }
@ -145,10 +158,10 @@ if ! checkNUMA; then
echo "systemd-run NUMAPolicy=default && NUMAMask=0 check without NUMA support" echo "systemd-run NUMAPolicy=default && NUMAMask=0 check without NUMA support"
runUnit='numa-systemd-run-test.service' runUnit='numa-systemd-run-test.service'
startJournalctl startJournalctl
systemd-run -p NUMAPolicy=default -p NUMAMask=0 --unit $runUnit sleep 1000 systemd-run -p NUMAPolicy=default -p NUMAMask=0 --unit "$runUnit" sleep 1000
sleep $sleepAfterStart sleep $sleepAfterStart
pid1StopUnit $runUnit pid1StopUnit "$runUnit"
stopJournalctl $runUnit stopJournalctl "$runUnit"
grep "NUMA support not available, ignoring" "$journalLog" grep "NUMA support not available, ignoring" "$journalLog"
else else
@ -156,43 +169,43 @@ else
writePID1NUMAPolicy "default" writePID1NUMAPolicy "default"
pid1ReloadWithStrace pid1ReloadWithStrace
# Kernel requires that nodemask argument is set to NULL when setting default policy # Kernel requires that nodemask argument is set to NULL when setting default policy
grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog grep "set_mempolicy(MPOL_DEFAULT, NULL" "$straceLog"
echo "PID1 NUMAPolicy support - Default policy w/ mask" echo "PID1 NUMAPolicy support - Default policy w/ mask"
writePID1NUMAPolicy "default" "0" writePID1NUMAPolicy "default" "0"
pid1ReloadWithStrace pid1ReloadWithStrace
grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog grep "set_mempolicy(MPOL_DEFAULT, NULL" "$straceLog"
echo "PID1 NUMAPolicy support - Bind policy w/o mask" echo "PID1 NUMAPolicy support - Bind policy w/o mask"
writePID1NUMAPolicy "bind" writePID1NUMAPolicy "bind"
pid1ReloadWithJournal pid1ReloadWithJournal
grep "Failed to set NUMA memory policy: Invalid argument" $journalLog grep "Failed to set NUMA memory policy: Invalid argument" "$journalLog"
echo "PID1 NUMAPolicy support - Bind policy w/ mask" echo "PID1 NUMAPolicy support - Bind policy w/ mask"
writePID1NUMAPolicy "bind" "0" writePID1NUMAPolicy "bind" "0"
pid1ReloadWithStrace pid1ReloadWithStrace
grep -P "set_mempolicy\(MPOL_BIND, \[0x0*1\]" $straceLog grep -P "set_mempolicy\(MPOL_BIND, \[0x0*1\]" "$straceLog"
echo "PID1 NUMAPolicy support - Interleave policy w/o mask" echo "PID1 NUMAPolicy support - Interleave policy w/o mask"
writePID1NUMAPolicy "interleave" writePID1NUMAPolicy "interleave"
pid1ReloadWithJournal pid1ReloadWithJournal
grep "Failed to set NUMA memory policy: Invalid argument" $journalLog grep "Failed to set NUMA memory policy: Invalid argument" "$journalLog"
echo "PID1 NUMAPolicy support - Interleave policy w/ mask" echo "PID1 NUMAPolicy support - Interleave policy w/ mask"
writePID1NUMAPolicy "interleave" "0" writePID1NUMAPolicy "interleave" "0"
pid1ReloadWithStrace pid1ReloadWithStrace
grep -P "set_mempolicy\(MPOL_INTERLEAVE, \[0x0*1\]" $straceLog grep -P "set_mempolicy\(MPOL_INTERLEAVE, \[0x0*1\]" "$straceLog"
echo "PID1 NUMAPolicy support - Preferred policy w/o mask" echo "PID1 NUMAPolicy support - Preferred policy w/o mask"
writePID1NUMAPolicy "preferred" writePID1NUMAPolicy "preferred"
pid1ReloadWithJournal pid1ReloadWithJournal
# Preferred policy with empty node mask is actually allowed and should reset allocation policy to default # Preferred policy with empty node mask is actually allowed and should reset allocation policy to default
! grep "Failed to set NUMA memory policy: Invalid argument" $journalLog grep "Failed to set NUMA memory policy: Invalid argument" "$journalLog" && { echo >&2 "unexpected pass"; exit 1; }
echo "PID1 NUMAPolicy support - Preferred policy w/ mask" echo "PID1 NUMAPolicy support - Preferred policy w/ mask"
writePID1NUMAPolicy "preferred" "0" writePID1NUMAPolicy "preferred" "0"
pid1ReloadWithStrace pid1ReloadWithStrace
grep -P "set_mempolicy\(MPOL_PREFERRED, \[0x0*1\]" $straceLog grep -P "set_mempolicy\(MPOL_PREFERRED, \[0x0*1\]" "$straceLog"
echo "PID1 NUMAPolicy support - Local policy w/o mask" echo "PID1 NUMAPolicy support - Local policy w/o mask"
writePID1NUMAPolicy "local" writePID1NUMAPolicy "local"
@ -202,136 +215,133 @@ else
# return a numerical constant instead (with a comment): # return a numerical constant instead (with a comment):
# set_mempolicy(0x4 /* MPOL_??? */, NULL, 0) = 0 # set_mempolicy(0x4 /* MPOL_??? */, NULL, 0) = 0
# Let's cover this scenario as well # Let's cover this scenario as well
grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" "$straceLog"
echo "PID1 NUMAPolicy support - Local policy w/ mask" echo "PID1 NUMAPolicy support - Local policy w/ mask"
writePID1NUMAPolicy "local" "0" writePID1NUMAPolicy "local" "0"
pid1ReloadWithStrace pid1ReloadWithStrace
grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" "$straceLog"
echo "Unit file NUMAPolicy support - Default policy w/o mask" echo "Unit file NUMAPolicy support - Default policy w/o mask"
writeTestUnitNUMAPolicy "default" writeTestUnitNUMAPolicy "default"
pid1StartUnitWithStrace $testUnit pid1StartUnitWithStrace "$testUnit"
systemctlCheckNUMAProperties $testUnit "default" systemctlCheckNUMAProperties "$testUnit" "default"
pid1StopUnit $testUnit pid1StopUnit "$testUnit"
grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog grep "set_mempolicy(MPOL_DEFAULT, NULL" "$straceLog"
echo "Unit file NUMAPolicy support - Default policy w/ mask" echo "Unit file NUMAPolicy support - Default policy w/ mask"
writeTestUnitNUMAPolicy "default" "0" writeTestUnitNUMAPolicy "default" "0"
pid1StartUnitWithStrace $testUnit pid1StartUnitWithStrace "$testUnit"
systemctlCheckNUMAProperties $testUnit "default" "0" systemctlCheckNUMAProperties "$testUnit" "default" "0"
pid1StopUnit $testUnit pid1StopUnit $testUnit
# Mask must be ignored # Mask must be ignored
grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog grep "set_mempolicy(MPOL_DEFAULT, NULL" "$straceLog"
echo "Unit file NUMAPolicy support - Bind policy w/o mask" echo "Unit file NUMAPolicy support - Bind policy w/o mask"
writeTestUnitNUMAPolicy "bind" writeTestUnitNUMAPolicy "bind"
pid1StartUnitWithJournal $testUnit pid1StartUnitWithJournal "$testUnit"
pid1StopUnit $testUnit pid1StopUnit "$testUnit"
grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" $journalLog grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" "$journalLog"
echo "Unit file NUMAPolicy support - Bind policy w/ mask" echo "Unit file NUMAPolicy support - Bind policy w/ mask"
writeTestUnitNUMAPolicy "bind" "0" writeTestUnitNUMAPolicy "bind" "0"
pid1StartUnitWithStrace $testUnit pid1StartUnitWithStrace "$testUnit"
systemctlCheckNUMAProperties $testUnit "bind" "0" systemctlCheckNUMAProperties "$testUnit" "bind" "0"
pid1StopUnit $testUnit pid1StopUnit "$testUnit"
grep -P "set_mempolicy\(MPOL_BIND, \[0x0*1\]" $straceLog grep -P "set_mempolicy\(MPOL_BIND, \[0x0*1\]" "$straceLog"
echo "Unit file NUMAPolicy support - Interleave policy w/o mask" echo "Unit file NUMAPolicy support - Interleave policy w/o mask"
writeTestUnitNUMAPolicy "interleave" writeTestUnitNUMAPolicy "interleave"
pid1StartUnitWithStrace $testUnit pid1StartUnitWithStrace "$testUnit"
pid1StopUnit $testUnit pid1StopUnit "$testUnit"
grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" $journalLog grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" "$journalLog"
echo "Unit file NUMAPolicy support - Interleave policy w/ mask" echo "Unit file NUMAPolicy support - Interleave policy w/ mask"
writeTestUnitNUMAPolicy "interleave" "0" writeTestUnitNUMAPolicy "interleave" "0"
pid1StartUnitWithStrace $testUnit pid1StartUnitWithStrace "$testUnit"
systemctlCheckNUMAProperties $testUnit "interleave" "0" systemctlCheckNUMAProperties "$testUnit" "interleave" "0"
pid1StopUnit $testUnit pid1StopUnit "$testUnit"
grep -P "set_mempolicy\(MPOL_INTERLEAVE, \[0x0*1\]" $straceLog grep -P "set_mempolicy\(MPOL_INTERLEAVE, \[0x0*1\]" "$straceLog"
echo "Unit file NUMAPolicy support - Preferred policy w/o mask" echo "Unit file NUMAPolicy support - Preferred policy w/o mask"
writeTestUnitNUMAPolicy "preferred" writeTestUnitNUMAPolicy "preferred"
pid1StartUnitWithJournal $testUnit pid1StartUnitWithJournal "$testUnit"
systemctlCheckNUMAProperties $testUnit "preferred" systemctlCheckNUMAProperties "$testUnit" "preferred"
pid1StopUnit $testUnit pid1StopUnit "$testUnit"
! grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" $journalLog grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" "$journalLog" && { echo >&2 "unexpected pass"; exit 1; }
echo "Unit file NUMAPolicy support - Preferred policy w/ mask" echo "Unit file NUMAPolicy support - Preferred policy w/ mask"
writeTestUnitNUMAPolicy "preferred" "0" writeTestUnitNUMAPolicy "preferred" "0"
pid1StartUnitWithStrace $testUnit pid1StartUnitWithStrace "$testUnit"
systemctlCheckNUMAProperties $testUnit "preferred" "0" systemctlCheckNUMAProperties "$testUnit" "preferred" "0"
pid1StopUnit $testUnit pid1StopUnit "$testUnit"
grep -P "set_mempolicy\(MPOL_PREFERRED, \[0x0*1\]" $straceLog grep -P "set_mempolicy\(MPOL_PREFERRED, \[0x0*1\]" "$straceLog"
echo "Unit file NUMAPolicy support - Local policy w/o mask" echo "Unit file NUMAPolicy support - Local policy w/o mask"
writeTestUnitNUMAPolicy "local" writeTestUnitNUMAPolicy "local"
pid1StartUnitWithStrace $testUnit pid1StartUnitWithStrace "$testUnit"
systemctlCheckNUMAProperties $testUnit "local" systemctlCheckNUMAProperties "$testUnit" "local"
pid1StopUnit $testUnit pid1StopUnit "$testUnit"
grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" "$straceLog"
echo "Unit file NUMAPolicy support - Local policy w/ mask" echo "Unit file NUMAPolicy support - Local policy w/ mask"
writeTestUnitNUMAPolicy "local" "0" writeTestUnitNUMAPolicy "local" "0"
pid1StartUnitWithStrace $testUnit pid1StartUnitWithStrace "$testUnit"
systemctlCheckNUMAProperties $testUnit "local" "0" systemctlCheckNUMAProperties "$testUnit" "local" "0"
pid1StopUnit $testUnit pid1StopUnit "$testUnit"
# Mask must be ignored # Mask must be ignored
grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" "$straceLog"
echo "Unit file CPUAffinity=NUMA support" echo "Unit file CPUAffinity=NUMA support"
writeTestUnitNUMAPolicy "bind" "0" writeTestUnitNUMAPolicy "bind" "0"
echo "CPUAffinity=numa" >>$testUnitNUMAConf echo "CPUAffinity=numa" >>"$testUnitNUMAConf"
systemctl daemon-reload systemctl daemon-reload
systemctl start $testUnit systemctl start "$testUnit"
systemctlCheckNUMAProperties $testUnit "bind" "0" systemctlCheckNUMAProperties "$testUnit" "bind" "0"
pid=$(systemctl show --value -p MainPID $testUnit) cpulist="$(cat /sys/devices/system/node/node0/cpulist)"
cpulist=$(cat /sys/devices/system/node/node0/cpulist) affinity_systemd="$(systemctl show --value -p CPUAffinity "$testUnit")"
affinity_systemd=$(systemctl show --value -p CPUAffinity $testUnit) [ "$cpulist" = "$affinity_systemd" ]
[ $cpulist = $affinity_systemd ] pid1StopUnit "$testUnit"
pid1StopUnit $testUnit
echo "systemd-run NUMAPolicy support" echo "systemd-run NUMAPolicy support"
runUnit='numa-systemd-run-test.service' runUnit='numa-systemd-run-test.service'
systemd-run -p NUMAPolicy=default --unit $runUnit sleep 1000 systemd-run -p NUMAPolicy=default --unit "$runUnit" sleep 1000
systemctlCheckNUMAProperties $runUnit "default" systemctlCheckNUMAProperties "$runUnit" "default"
pid1StopUnit $runUnit pid1StopUnit "$runUnit"
systemd-run -p NUMAPolicy=default -p NUMAMask=0 --unit $runUnit sleep 1000 systemd-run -p NUMAPolicy=default -p NUMAMask=0 --unit "$runUnit" sleep 1000
systemctlCheckNUMAProperties $runUnit "default" "" systemctlCheckNUMAProperties "$runUnit" "default" ""
pid1StopUnit $runUnit pid1StopUnit "$runUnit"
systemd-run -p NUMAPolicy=bind -p NUMAMask=0 --unit $runUnit sleep 1000 systemd-run -p NUMAPolicy=bind -p NUMAMask=0 --unit "$runUnit" sleep 1000
systemctlCheckNUMAProperties $runUnit "bind" "0" systemctlCheckNUMAProperties "$runUnit" "bind" "0"
pid1StopUnit $runUnit pid1StopUnit "$runUnit"
systemd-run -p NUMAPolicy=interleave -p NUMAMask=0 --unit $runUnit sleep 1000 systemd-run -p NUMAPolicy=interleave -p NUMAMask=0 --unit "$runUnit" sleep 1000
systemctlCheckNUMAProperties $runUnit "interleave" "0" systemctlCheckNUMAProperties "$runUnit" "interleave" "0"
pid1StopUnit $runUnit pid1StopUnit "$runUnit"
systemd-run -p NUMAPolicy=preferred -p NUMAMask=0 --unit $runUnit sleep 1000 systemd-run -p NUMAPolicy=preferred -p NUMAMask=0 --unit "$runUnit" sleep 1000
systemctlCheckNUMAProperties $runUnit "preferred" "0" systemctlCheckNUMAProperties "$runUnit" "preferred" "0"
pid1StopUnit $runUnit pid1StopUnit "$runUnit"
systemd-run -p NUMAPolicy=local --unit $runUnit sleep 1000 systemd-run -p NUMAPolicy=local --unit "$runUnit" sleep 1000
systemctlCheckNUMAProperties $runUnit "local" systemctlCheckNUMAProperties "$runUnit" "local"
pid1StopUnit $runUnit pid1StopUnit "$runUnit"
systemd-run -p NUMAPolicy=local -p NUMAMask=0 --unit $runUnit sleep 1000 systemd-run -p NUMAPolicy=local -p NUMAMask=0 --unit "$runUnit" sleep 1000
systemctlCheckNUMAProperties $runUnit "local" "" systemctlCheckNUMAProperties "$runUnit" "local" ""
pid1StopUnit $runUnit pid1StopUnit "$runUnit"
systemd-run -p NUMAPolicy=local -p NUMAMask=0 -p CPUAffinity=numa --unit $runUnit sleep 1000
systemctlCheckNUMAProperties $runUnit "local" ""
systemctl cat $runUnit | grep -q 'CPUAffinity=numa'
pid1StopUnit $runUnit
systemd-run -p NUMAPolicy=local -p NUMAMask=0 -p CPUAffinity=numa --unit "$runUnit" sleep 1000
systemctlCheckNUMAProperties "$runUnit" "local" ""
systemctl cat "$runUnit" | grep -q 'CPUAffinity=numa'
pid1StopUnit "$runUnit"
fi fi
# Cleanup # Cleanup
rm -rf $testDir rm -rf "$confDir"
rm -rf $confDir
systemctl daemon-reload systemctl daemon-reload
systemd-analyze log-level info systemd-analyze log-level info

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 sts=4 et filetype=sh # ex: ts=8 sw=4 sts=4 et filetype=sh
set -ex set -eux
set -o pipefail set -o pipefail
systemd-mount -p RuntimeDirectory=hoge -p RuntimeDirectoryPreserve=yes -t tmpfs tmpfs /tmp/aaa systemd-mount -p RuntimeDirectory=hoge -p RuntimeDirectoryPreserve=yes -t tmpfs tmpfs /tmp/aaa

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
systemd-analyze log-level debug systemd-analyze log-level debug
@ -14,11 +14,11 @@ start_test_service() {
} }
dbus_freeze() { dbus_freeze() {
local suffix= local name object_path suffix
suffix="${1##*.}"
local name="$(echo ${1%.$suffix} | sed s/-/_2d/g)" suffix="${1##*.}"
local object_path="/org/freedesktop/systemd1/unit/${name}_2e${suffix}" name="${1%.$suffix}"
object_path="/org/freedesktop/systemd1/unit/${name//-/_2d}_2e${suffix}"
busctl call \ busctl call \
org.freedesktop.systemd1 \ org.freedesktop.systemd1 \
@ -28,11 +28,11 @@ dbus_freeze() {
} }
dbus_thaw() { dbus_thaw() {
local suffix= local name object_path suffix
suffix="${1##*.}"
local name="$(echo ${1%.$suffix} | sed s/-/_2d/g)" suffix="${1##*.}"
local object_path="/org/freedesktop/systemd1/unit/${name}_2e${suffix}" name="${1%.$suffix}"
object_path="/org/freedesktop/systemd1/unit/${name//-/_2d}_2e${suffix}"
busctl call \ busctl call \
org.freedesktop.systemd1 \ org.freedesktop.systemd1 \
@ -62,11 +62,11 @@ dbus_thaw_unit() {
} }
dbus_can_freeze() { dbus_can_freeze() {
local suffix= local name object_path suffix
suffix="${1##*.}"
local name="$(echo ${1%.$suffix} | sed s/-/_2d/g)" suffix="${1##*.}"
local object_path="/org/freedesktop/systemd1/unit/${name}_2e${suffix}" name="${1%.$suffix}"
object_path="/org/freedesktop/systemd1/unit/${name//-/_2d}_2e${suffix}"
busctl get-property \ busctl get-property \
org.freedesktop.systemd1 \ org.freedesktop.systemd1 \
@ -76,11 +76,11 @@ dbus_can_freeze() {
} }
check_freezer_state() { check_freezer_state() {
local suffix= local name object_path suffix
suffix="${1##*.}"
local name="$(echo ${1%.$suffix} | sed s/-/_2d/g)" suffix="${1##*.}"
local object_path="/org/freedesktop/systemd1/unit/${name}_2e${suffix}" name="${1%.$suffix}"
object_path="/org/freedesktop/systemd1/unit/${name//-/_2d}_2e${suffix}"
state=$(busctl get-property \ state=$(busctl get-property \
org.freedesktop.systemd1 \ org.freedesktop.systemd1 \

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
systemd-analyze log-level debug systemd-analyze log-level debug
@ -18,12 +18,12 @@ ExecReload=/bin/false
EOF EOF
systemctl daemon-reload systemctl daemon-reload
systemctl start $SERVICE_NAME systemctl start "$SERVICE_NAME"
systemctl status $SERVICE_NAME systemctl status "$SERVICE_NAME"
# The reload SHOULD fail but SHOULD NOT affect the service state # The reload SHOULD fail but SHOULD NOT affect the service state
systemctl reload $SERVICE_NAME && { echo 'unexpected success'; exit 1; } systemctl reload "$SERVICE_NAME" && { echo 'unexpected success'; exit 1; }
systemctl status $SERVICE_NAME systemctl status "$SERVICE_NAME"
systemctl stop $SERVICE_NAME systemctl stop "$SERVICE_NAME"
echo "[#2] Failing ExecReload= should not kill the service (multiple ExecReload=)" echo "[#2] Failing ExecReload= should not kill the service (multiple ExecReload=)"
@ -36,12 +36,12 @@ ExecReload=/bin/true
EOF EOF
systemctl daemon-reload systemctl daemon-reload
systemctl start $SERVICE_NAME systemctl start "$SERVICE_NAME"
systemctl status $SERVICE_NAME systemctl status "$SERVICE_NAME"
# The reload SHOULD fail but SHOULD NOT affect the service state # The reload SHOULD fail but SHOULD NOT affect the service state
systemctl reload $SERVICE_NAME && { echo 'unexpected success'; exit 1; } systemctl reload "$SERVICE_NAME" && { echo 'unexpected success'; exit 1; }
systemctl status $SERVICE_NAME systemctl status "$SERVICE_NAME"
systemctl stop $SERVICE_NAME systemctl stop "$SERVICE_NAME"
echo "[#3] Failing ExecReload=- should not affect reload's exit code" echo "[#3] Failing ExecReload=- should not affect reload's exit code"
cat >"$SERVICE_PATH" <<EOF cat >"$SERVICE_PATH" <<EOF
@ -51,11 +51,11 @@ ExecReload=-/bin/false
EOF EOF
systemctl daemon-reload systemctl daemon-reload
systemctl start $SERVICE_NAME systemctl start "$SERVICE_NAME"
systemctl status $SERVICE_NAME systemctl status "$SERVICE_NAME"
systemctl reload $SERVICE_NAME systemctl reload "$SERVICE_NAME"
systemctl status $SERVICE_NAME systemctl status "$SERVICE_NAME"
systemctl stop $SERVICE_NAME systemctl stop "$SERVICE_NAME"
systemd-analyze log-level info systemd-analyze log-level info

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
systemd-analyze log-level debug systemd-analyze log-level debug

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
# wait this many secs for each test service to succeed in what is being tested # wait this many secs for each test service to succeed in what is being tested
@ -12,7 +12,7 @@ systemd-analyze log-target console
systemd-run --unit=one -p Type=oneshot -p Restart=on-failure /bin/bash -c "exit 1" \ systemd-run --unit=one -p Type=oneshot -p Restart=on-failure /bin/bash -c "exit 1" \
&& { echo 'unexpected success'; exit 1; } && { echo 'unexpected success'; exit 1; }
for ((secs=0; secs<$MAX_SECS; secs++)); do for ((secs = 0; secs < MAX_SECS; secs++)); do
[[ "$(systemctl show one.service -P NRestarts)" -le 0 ]] || break [[ "$(systemctl show one.service -P NRestarts)" -le 0 ]] || break
sleep 1 sleep 1
done done
@ -35,7 +35,7 @@ systemd-run --unit=two \
&& { echo 'unexpected success'; exit 1; } && { echo 'unexpected success'; exit 1; }
# wait for at least 3 restarts # wait for at least 3 restarts
for ((secs=0; secs<$MAX_SECS; secs++)); do for ((secs = 0; secs < MAX_SECS; secs++)); do
[[ $(cat $TMP_FILE) != "aaa" ]] || break [[ $(cat $TMP_FILE) != "aaa" ]] || break
sleep 1 sleep 1
done done

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
systemd-analyze log-level debug systemd-analyze log-level debug

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
systemd-analyze log-level debug systemd-analyze log-level debug
@ -7,6 +7,7 @@ systemd-analyze log-level debug
runas() { runas() {
declare userid=$1 declare userid=$1
shift shift
# shellcheck disable=SC2016
su "$userid" -s /bin/sh -c 'XDG_RUNTIME_DIR=/run/user/$UID exec "$@"' -- sh "$@" su "$userid" -s /bin/sh -c 'XDG_RUNTIME_DIR=/run/user/$UID exec "$@"' -- sh "$@"
} }
@ -46,6 +47,7 @@ runas testuser systemd-run --wait --user --unit=test-protect-home-tmpfs \
-P test ! -e /home/testuser -P test ! -e /home/testuser
# Confirm that home, /root, and /run/user are inaccessible under "yes" # Confirm that home, /root, and /run/user are inaccessible under "yes"
# shellcheck disable=SC2016
runas testuser systemd-run --wait --user --unit=test-protect-home-yes \ runas testuser systemd-run --wait --user --unit=test-protect-home-yes \
-p PrivateUsers=yes -p ProtectHome=yes \ -p PrivateUsers=yes -p ProtectHome=yes \
-P bash -c ' -P bash -c '

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
systemd-analyze log-level debug systemd-analyze log-level debug

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
# Check if homectl is installed, and if it isn't bail out early instead of failing # Check if homectl is installed, and if it isn't bail out early instead of failing
@ -14,8 +14,9 @@ inspect() {
# avoid unexpected fails. To see the full outputs of both homectl & # avoid unexpected fails. To see the full outputs of both homectl &
# userdbctl (for debugging purposes) drop the fields just before the # userdbctl (for debugging purposes) drop the fields just before the
# comparison. # comparison.
homectl inspect $1 | tee /tmp/a local USERNAME="${1:?missing argument}"
userdbctl user $1 | tee /tmp/b homectl inspect "$USERNAME" | tee /tmp/a
userdbctl user "$USERNAME" | tee /tmp/b
diff -I '/^\s*Disk (Size|Free|Floor|Ceiling):/' /tmp/{a,b} diff -I '/^\s*Disk (Size|Free|Floor|Ceiling):/' /tmp/{a,b}
rm /tmp/{a,b} rm /tmp/{a,b}

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
systemd-analyze log-level debug systemd-analyze log-level debug

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 sts=4 et filetype=sh # ex: ts=8 sw=4 sts=4 et filetype=sh
set -ex set -eux
cat >/run/systemd/system/testservice-48.target <<EOF cat >/run/systemd/system/testservice-48.target <<EOF
[Unit] [Unit]

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
echo "MARKER_FIXED" >/run/testservice-49-fixed echo "MARKER_FIXED" >/run/testservice-49-fixed
mkdir -p /run/inaccessible mkdir -p /run/inaccessible

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 sts=4 et filetype=sh # ex: ts=8 sw=4 sts=4 et filetype=sh
set -ex set -eux
set -o pipefail set -o pipefail
export SYSTEMD_LOG_LEVEL=debug export SYSTEMD_LOG_LEVEL=debug
@ -26,48 +26,48 @@ trap cleanup EXIT
cp /usr/share/minimal* "${image_dir}/" cp /usr/share/minimal* "${image_dir}/"
image="${image_dir}/minimal_0" image="${image_dir}/minimal_0"
roothash="$(cat ${image}.roothash)" roothash="$(cat "${image}.roothash")"
os_release=$(test -e /etc/os-release && echo /etc/os-release || echo /usr/lib/os-release) os_release="$(test -e /etc/os-release && echo /etc/os-release || echo /usr/lib/os-release)"
systemd-dissect --json=short ${image}.raw | grep -q -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"' systemd-dissect --json=short "${image}.raw" | grep -q -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"'
systemd-dissect ${image}.raw | grep -q -F "MARKER=1" systemd-dissect "${image}.raw" | grep -q -F "MARKER=1"
systemd-dissect ${image}.raw | grep -q -F -f <(sed 's/"//g' $os_release) systemd-dissect "${image}.raw" | grep -q -F -f <(sed 's/"//g' "$os_release")
mv ${image}.verity ${image}.fooverity mv "${image}.verity" "${image}.fooverity"
mv ${image}.roothash ${image}.foohash mv "${image}.roothash" "${image}.foohash"
systemd-dissect --json=short ${image}.raw --root-hash=${roothash} --verity-data=${image}.fooverity | grep -q -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"' systemd-dissect --json=short "${image}.raw" --root-hash="${roothash}" --verity-data="${image}.fooverity" | grep -q -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"'
systemd-dissect ${image}.raw --root-hash=${roothash} --verity-data=${image}.fooverity | grep -q -F "MARKER=1" systemd-dissect "${image}.raw" --root-hash="${roothash}" --verity-data="${image}.fooverity" | grep -q -F "MARKER=1"
systemd-dissect ${image}.raw --root-hash=${roothash} --verity-data=${image}.fooverity | grep -q -F -f <(sed 's/"//g' $os_release) systemd-dissect "${image}.raw" --root-hash="${roothash}" --verity-data="${image}.fooverity" | grep -q -F -f <(sed 's/"//g' "$os_release")
mv ${image}.fooverity ${image}.verity mv "${image}.fooverity" "${image}.verity"
mv ${image}.foohash ${image}.roothash mv "${image}.foohash" "${image}.roothash"
mkdir -p ${image_dir}/mount ${image_dir}/mount2 mkdir -p "${image_dir}/mount" "${image_dir}/mount2"
systemd-dissect --mount ${image}.raw ${image_dir}/mount systemd-dissect --mount "${image}.raw" "${image_dir}/mount"
cat ${image_dir}/mount/usr/lib/os-release | grep -q -F -f $os_release grep -q -F -f "$os_release" "${image_dir}/mount/usr/lib/os-release"
cat ${image_dir}/mount/etc/os-release | grep -q -F -f $os_release grep -q -F -f "$os_release" "${image_dir}/mount/etc/os-release"
cat ${image_dir}/mount/usr/lib/os-release | grep -q -F "MARKER=1" grep -q -F "MARKER=1" "${image_dir}/mount/usr/lib/os-release"
# Verity volume should be shared (opened only once) # Verity volume should be shared (opened only once)
systemd-dissect --mount ${image}.raw ${image_dir}/mount2 systemd-dissect --mount "${image}.raw" "${image_dir}/mount2"
verity_count=$(ls -1 /dev/mapper/ | grep -c verity) verity_count=$(find /dev/mapper/ -name "*verity*" | wc -l)
# In theory we should check that count is exactly one. In practice, libdevmapper # In theory we should check that count is exactly one. In practice, libdevmapper
# randomly and unpredictably fails with an unhelpful EINVAL when a device is open # randomly and unpredictably fails with an unhelpful EINVAL when a device is open
# (and even mounted and in use), so best-effort is the most we can do for now # (and even mounted and in use), so best-effort is the most we can do for now
if [ ${verity_count} -lt 1 ]; then if [ "${verity_count}" -lt 1 ]; then
echo "Verity device ${image}.raw not found in /dev/mapper/" echo "Verity device ${image}.raw not found in /dev/mapper/"
exit 1 exit 1
fi fi
umount ${image_dir}/mount umount "${image_dir}/mount"
umount ${image_dir}/mount2 umount "${image_dir}/mount2"
systemd-run -t -p RootImage=${image}.raw cat /usr/lib/os-release | grep -q -F "MARKER=1" systemd-run -t -p RootImage="${image}.raw" cat /usr/lib/os-release | grep -q -F "MARKER=1"
mv ${image}.verity ${image}.fooverity mv "${image}.verity" "${image}.fooverity"
mv ${image}.roothash ${image}.foohash mv "${image}.roothash" "${image}.foohash"
systemd-run -t -p RootImage=${image}.raw -p RootHash=${image}.foohash -p RootVerity=${image}.fooverity cat /usr/lib/os-release | grep -q -F "MARKER=1" systemd-run -t -p RootImage="${image}.raw" -p RootHash="${image}.foohash" -p RootVerity="${image}.fooverity" cat /usr/lib/os-release | grep -q -F "MARKER=1"
# Let's use the long option name just here as a test # Let's use the long option name just here as a test
systemd-run -t --property RootImage=${image}.raw --property RootHash=${roothash} --property RootVerity=${image}.fooverity cat /usr/lib/os-release | grep -q -F "MARKER=1" systemd-run -t --property RootImage="${image}.raw" --property RootHash="${roothash}" --property RootVerity="${image}.fooverity" cat /usr/lib/os-release | grep -q -F "MARKER=1"
mv ${image}.fooverity ${image}.verity mv "${image}.fooverity" "${image}.verity"
mv ${image}.foohash ${image}.roothash mv "${image}.foohash" "${image}.roothash"
# Make a GPT disk on the fly, with the squashfs as partition 1 and the verity hash tree as partition 2 # Make a GPT disk on the fly, with the squashfs as partition 1 and the verity hash tree as partition 2
machine="$(uname -m)" machine="$(uname -m)"
@ -100,51 +100,54 @@ else
exit 1 exit 1
fi fi
# du rounds up to block size, which is more helpful for partitioning # du rounds up to block size, which is more helpful for partitioning
root_size="$(du -k ${image}.raw | cut -f1)" root_size="$(du -k "${image}.raw" | cut -f1)"
verity_size="$(du -k ${image}.verity | cut -f1)" verity_size="$(du -k "${image}.verity" | cut -f1)"
# 4MB seems to be the minimum size blkid will accept, below that probing fails # 4MB seems to be the minimum size blkid will accept, below that probing fails
dd if=/dev/zero of=${image}.gpt bs=512 count=$((8192+${root_size}*2+${verity_size}*2)) dd if=/dev/zero of="${image}.gpt" bs=512 count=$((8192+root_size*2+verity_size*2))
# sfdisk seems unhappy if the size overflows into the next unit, eg: 1580KiB will be interpreted as 1MiB # sfdisk seems unhappy if the size overflows into the next unit, eg: 1580KiB will be interpreted as 1MiB
# so do some basic rounding up if the minimal image is more than 1 MB # so do some basic rounding up if the minimal image is more than 1 MB
if [ ${root_size} -ge 1024 ]; then if [ "${root_size}" -ge 1024 ]; then
root_size="$((${root_size}/1024 + 1))MiB" root_size="$((root_size/1024 + 1))MiB"
else else
root_size="${root_size}KiB" root_size="${root_size}KiB"
fi fi
verity_size="$((${verity_size} * 2))KiB" verity_size="$((verity_size * 2))KiB"
uuid="$(head -c 32 ${image}.roothash | cut -c -8)-$(head -c 32 ${image}.roothash | cut -c 9-12)-$(head -c 32 ${image}.roothash | cut -c 13-16)-$(head -c 32 ${image}.roothash | cut -c 17-20)-$(head -c 32 ${image}.roothash | cut -c 21-)" # Construct a UUID from hash
echo -e "label: gpt\nsize=${root_size}, type=${root_guid}, uuid=${uuid}" | sfdisk ${image}.gpt # input: 11111111222233334444555566667777
uuid="$(tail -c 32 ${image}.roothash | cut -c -8)-$(tail -c 32 ${image}.roothash | cut -c 9-12)-$(tail -c 32 ${image}.roothash | cut -c 13-16)-$(tail -c 32 ${image}.roothash | cut -c 17-20)-$(tail -c 32 ${image}.roothash | cut -c 21-)" # output: 11111111-2222-3333-4444-555566667777
echo -e "size=${verity_size}, type=${verity_guid}, uuid=${uuid}" | sfdisk ${image}.gpt --append uuid="$(head -c 32 "${image}.roothash" | sed -r 's/(.{8})(.{4})(.{4})(.{4})(.+)/\1-\2-\3-\4-\5/')"
sfdisk --part-label ${image}.gpt 1 "Root Partition" echo -e "label: gpt\nsize=${root_size}, type=${root_guid}, uuid=${uuid}" | sfdisk "${image}.gpt"
sfdisk --part-label ${image}.gpt 2 "Verity Partition" uuid="$(tail -c 32 "${image}.roothash" | sed -r 's/(.{8})(.{4})(.{4})(.{4})(.+)/\1-\2-\3-\4-\5/')"
loop="$(losetup --show -P -f ${image}.gpt)" echo -e "size=${verity_size}, type=${verity_guid}, uuid=${uuid}" | sfdisk "${image}.gpt" --append
dd if=${image}.raw of=${loop}p1 sfdisk --part-label "${image}.gpt" 1 "Root Partition"
dd if=${image}.verity of=${loop}p2 sfdisk --part-label "${image}.gpt" 2 "Verity Partition"
losetup -d ${loop} loop="$(losetup --show -P -f "${image}.gpt")"
dd if="${image}.raw" of="${loop}p1"
dd if="${image}.verity" of="${loop}p2"
losetup -d "${loop}"
# Derive partition UUIDs from root hash, in UUID syntax # Derive partition UUIDs from root hash, in UUID syntax
ROOT_UUID=$(systemd-id128 -u show $(head -c 32 ${image}.roothash) -u | tail -n 1 | cut -b 6-) ROOT_UUID="$(systemd-id128 -u show "$(head -c 32 "${image}.roothash")" -u | tail -n 1 | cut -b 6-)"
VERITY_UUID=$(systemd-id128 -u show $(tail -c 32 ${image}.roothash) -u | tail -n 1 | cut -b 6-) VERITY_UUID="$(systemd-id128 -u show "$(tail -c 32 "${image}.roothash")" -u | tail -n 1 | cut -b 6-)"
systemd-dissect --json=short --root-hash ${roothash} ${image}.gpt | grep -q '{"rw":"ro","designator":"root","partition_uuid":"'$ROOT_UUID'","partition_label":"Root Partition","fstype":"squashfs","architecture":"'$architecture'","verity":"yes","node":' systemd-dissect --json=short --root-hash "${roothash}" "${image}.gpt" | grep -q '{"rw":"ro","designator":"root","partition_uuid":"'"$ROOT_UUID"'","partition_label":"Root Partition","fstype":"squashfs","architecture":"'"$architecture"'","verity":"yes","node":'
systemd-dissect --json=short --root-hash ${roothash} ${image}.gpt | grep -q '{"rw":"ro","designator":"root-verity","partition_uuid":"'$VERITY_UUID'","partition_label":"Verity Partition","fstype":"DM_verity_hash","architecture":"'$architecture'","verity":null,"node":' systemd-dissect --json=short --root-hash "${roothash}" "${image}.gpt" | grep -q '{"rw":"ro","designator":"root-verity","partition_uuid":"'"$VERITY_UUID"'","partition_label":"Verity Partition","fstype":"DM_verity_hash","architecture":"'"$architecture"'","verity":null,"node":'
systemd-dissect --root-hash ${roothash} ${image}.gpt | grep -q -F "MARKER=1" systemd-dissect --root-hash "${roothash}" "${image}.gpt" | grep -q -F "MARKER=1"
systemd-dissect --root-hash ${roothash} ${image}.gpt | grep -q -F -f <(sed 's/"//g' $os_release) systemd-dissect --root-hash "${roothash}" "${image}.gpt" | grep -q -F -f <(sed 's/"//g' "$os_release")
systemd-dissect --root-hash ${roothash} --mount ${image}.gpt ${image_dir}/mount systemd-dissect --root-hash "${roothash}" --mount "${image}.gpt" "${image_dir}/mount"
cat ${image_dir}/mount/usr/lib/os-release | grep -q -F -f $os_release grep -q -F -f "$os_release" "${image_dir}/mount/usr/lib/os-release"
cat ${image_dir}/mount/etc/os-release | grep -q -F -f $os_release grep -q -F -f "$os_release" "${image_dir}/mount/etc/os-release"
cat ${image_dir}/mount/usr/lib/os-release | grep -q -F "MARKER=1" grep -q -F "MARKER=1" "${image_dir}/mount/usr/lib/os-release"
umount ${image_dir}/mount umount "${image_dir}/mount"
# add explicit -p MountAPIVFS=yes once to test the parser # add explicit -p MountAPIVFS=yes once to test the parser
systemd-run -t -p RootImage=${image}.gpt -p RootHash=${roothash} -p MountAPIVFS=yes cat /usr/lib/os-release | grep -q -F "MARKER=1" systemd-run -t -p RootImage="${image}.gpt" -p RootHash="${roothash}" -p MountAPIVFS=yes cat /usr/lib/os-release | grep -q -F "MARKER=1"
systemd-run -t -p RootImage=${image}.raw -p RootImageOptions="root:nosuid,dev home:ro,dev ro,noatime" mount | grep -F "squashfs" | grep -q -F "nosuid" systemd-run -t -p RootImage="${image}.raw" -p RootImageOptions="root:nosuid,dev home:ro,dev ro,noatime" mount | grep -F "squashfs" | grep -q -F "nosuid"
systemd-run -t -p RootImage=${image}.gpt -p RootImageOptions="root:ro,noatime root:ro,dev" mount | grep -F "squashfs" | grep -q -F "noatime" systemd-run -t -p RootImage="${image}.gpt" -p RootImageOptions="root:ro,noatime root:ro,dev" mount | grep -F "squashfs" | grep -q -F "noatime"
mkdir -p mkdir -p ${image_dir}/result mkdir -p "${image_dir}/result"
cat >/run/systemd/system/testservice-50a.service <<EOF cat >/run/systemd/system/testservice-50a.service <<EOF
[Service] [Service]
Type=oneshot Type=oneshot
@ -156,8 +159,8 @@ RootImageOptions=root:ro,noatime home:ro,dev relatime,dev
RootImageOptions=nosuid,dev RootImageOptions=nosuid,dev
EOF EOF
systemctl start testservice-50a.service systemctl start testservice-50a.service
grep -F "squashfs" ${image_dir}/result/a | grep -q -F "noatime" grep -F "squashfs" "${image_dir}/result/a" | grep -q -F "noatime"
grep -F "squashfs" ${image_dir}/result/a | grep -q -F -v "nosuid" grep -F "squashfs" "${image_dir}/result/a" | grep -q -F -v "nosuid"
cat >/run/systemd/system/testservice-50b.service <<EOF cat >/run/systemd/system/testservice-50b.service <<EOF
[Service] [Service]
@ -172,7 +175,7 @@ RootImageOptions=home:ro,dev nosuid,dev,%%foo
MountAPIVFS=yes MountAPIVFS=yes
EOF EOF
systemctl start testservice-50b.service systemctl start testservice-50b.service
grep -F "squashfs" ${image_dir}/result/b | grep -q -F "noatime" grep -F "squashfs" "${image_dir}/result/b" | grep -q -F "noatime"
# Check that specifier escape is applied %%foo → %foo # Check that specifier escape is applied %%foo → %foo
busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1/unit/testservice_2d50b_2eservice org.freedesktop.systemd1.Service RootImageOptions | grep -F "nosuid,dev,%foo" busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1/unit/testservice_2d50b_2eservice org.freedesktop.systemd1.Service RootImageOptions | grep -F "nosuid,dev,%foo"
@ -184,9 +187,9 @@ systemd-run -t -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2:nos
systemd-run -t -p MountImages="${image}.gpt:/run/img1:root:nosuid ${image}.raw:/run/img2:home:suid" mount | grep -F "squashfs" | grep -q -F "nosuid" systemd-run -t -p MountImages="${image}.gpt:/run/img1:root:nosuid ${image}.raw:/run/img2:home:suid" mount | grep -F "squashfs" | grep -q -F "nosuid"
systemd-run -t -p MountImages="${image}.raw:/run/img2\:3" cat /run/img2:3/usr/lib/os-release | grep -q -F "MARKER=1" systemd-run -t -p MountImages="${image}.raw:/run/img2\:3" cat /run/img2:3/usr/lib/os-release | grep -q -F "MARKER=1"
systemd-run -t -p MountImages="${image}.raw:/run/img2\:3:nosuid" mount | grep -F "squashfs" | grep -q -F "nosuid" systemd-run -t -p MountImages="${image}.raw:/run/img2\:3:nosuid" mount | grep -F "squashfs" | grep -q -F "nosuid"
systemd-run -t -p TemporaryFileSystem=/run -p RootImage=${image}.raw -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" cat /usr/lib/os-release | grep -q -F "MARKER=1" systemd-run -t -p TemporaryFileSystem=/run -p RootImage="${image}.raw" -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" cat /usr/lib/os-release | grep -q -F "MARKER=1"
systemd-run -t -p TemporaryFileSystem=/run -p RootImage=${image}.raw -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1" systemd-run -t -p TemporaryFileSystem=/run -p RootImage="${image}.raw" -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1"
systemd-run -t -p TemporaryFileSystem=/run -p RootImage=${image}.gpt -p RootHash=${roothash} -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1" systemd-run -t -p TemporaryFileSystem=/run -p RootImage="${image}.gpt" -p RootHash="${roothash}" -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1"
cat >/run/systemd/system/testservice-50c.service <<EOF cat >/run/systemd/system/testservice-50c.service <<EOF
[Service] [Service]
MountAPIVFS=yes MountAPIVFS=yes
@ -201,9 +204,9 @@ BindPaths=${image_dir}/result:/run/result
Type=oneshot Type=oneshot
EOF EOF
systemctl start testservice-50c.service systemctl start testservice-50c.service
grep -q -F "MARKER=1" ${image_dir}/result/c grep -q -F "MARKER=1" "${image_dir}/result/c"
grep -F "squashfs" ${image_dir}/result/c | grep -q -F "noatime" grep -F "squashfs" "${image_dir}/result/c" | grep -q -F "noatime"
grep -F "squashfs" ${image_dir}/result/c | grep -q -F -v "nosuid" grep -F "squashfs" "${image_dir}/result/c" | grep -q -F -v "nosuid"
# Adding a new mounts at runtime works if the unit is in the active state, # Adding a new mounts at runtime works if the unit is in the active state,
# so use Type=notify to make sure there's no race condition in the test # so use Type=notify to make sure there's no race condition in the test
@ -218,7 +221,7 @@ ExecStart=/bin/sh -c 'systemd-notify --ready; while ! grep -q -F MARKER /tmp/img
EOF EOF
systemctl start testservice-50d.service systemctl start testservice-50d.service
systemctl mount-image --mkdir testservice-50d.service ${image}.raw /tmp/img root:nosuid systemctl mount-image --mkdir testservice-50d.service "${image}.raw" /tmp/img root:nosuid
while systemctl show -P SubState testservice-50d.service | grep -q running while systemctl show -P SubState testservice-50d.service | grep -q running
do do
@ -228,12 +231,12 @@ done
systemctl is-active testservice-50d.service systemctl is-active testservice-50d.service
# ExtensionImages will set up an overlay # ExtensionImages will set up an overlay
systemd-run -t --property ExtensionImages=/usr/share/app0.raw --property RootImage=${image}.raw cat /opt/script0.sh | grep -q -F "extension-release.app0" systemd-run -t --property ExtensionImages=/usr/share/app0.raw --property RootImage="${image}.raw" cat /opt/script0.sh | grep -q -F "extension-release.app0"
systemd-run -t --property ExtensionImages=/usr/share/app0.raw --property RootImage=${image}.raw cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" systemd-run -t --property ExtensionImages=/usr/share/app0.raw --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
systemd-run -t --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage=${image}.raw cat /opt/script0.sh | grep -q -F "extension-release.app0" systemd-run -t --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /opt/script0.sh | grep -q -F "extension-release.app0"
systemd-run -t --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage=${image}.raw cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" systemd-run -t --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
systemd-run -t --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage=${image}.raw cat /opt/script1.sh | grep -q -F "extension-release.app1" systemd-run -t --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /opt/script1.sh | grep -q -F "extension-release.app1"
systemd-run -t --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage=${image}.raw cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1" systemd-run -t --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1"
cat >/run/systemd/system/testservice-50e.service <<EOF cat >/run/systemd/system/testservice-50e.service <<EOF
[Service] [Service]
MountAPIVFS=yes MountAPIVFS=yes

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
systemctl start testsuite-51-repro-1 systemctl start testsuite-51-repro-1

View File

@ -1,8 +1,8 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
>/failed : >/failed
# Reset host date to current time, 3 days in the past. # Reset host date to current time, 3 days in the past.
date -s "-3 days" date -s "-3 days"

View File

@ -1,5 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex # shellcheck disable=SC2016
set -eux
systemd-analyze log-level debug systemd-analyze log-level debug

View File

@ -1,32 +1,39 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -eu -o pipefail # Don't use set -x here, since it generates a lot of output and slows
# the script down, causing unexpected test fails.
set -eu
set -o pipefail
PAGE_SIZE=$(getconf PAGE_SIZE) PAGE_SIZE=$(getconf PAGE_SIZE)
BLOAT_ITERATION_TARGET=$(( 100 << 20 )) # 100 MB BLOAT_ITERATION_TARGET=$((100 << 20)) # 100 MB
BLOAT_HOLDER=() BLOAT_HOLDER=()
PID="$$" PID="$$"
function bloat { function bloat {
local set_size=$(cat "/proc/$PID/statm" | cut -d " " -f2) local set_size mem_usage target_mem_size
local mem_usage=$(( "$set_size" * "$PAGE_SIZE" ))
local target_mem_size=$(( "$mem_usage" + "$1" )) # Following `| cat` weirdness is intentional to generate some reclaim
# activity in case there's no swap available.
set_size=$(cut -d " " -f2 "/proc/$PID/statm" | cat)
mem_usage=$((set_size * PAGE_SIZE))
target_mem_size=$((mem_usage + $1))
BLOAT_HOLDER=() BLOAT_HOLDER=()
while [[ "$mem_usage" -lt "$target_mem_size" ]]; do while [[ "$mem_usage" -lt "$target_mem_size" ]]; do
echo "target $target_mem_size" echo "target $target_mem_size"
echo "mem usage $mem_usage" echo "mem usage $mem_usage"
BLOAT_HOLDER+=( $(printf "%0.sg" {1..1000000}) ) BLOAT_HOLDER+=("$(printf "=%0.s" {1..1000000})")
set_size=$(cat "/proc/$PID/statm" | cut -d " " -f2) set_size=$(cut -d " " -f2 "/proc/$PID/statm" | cat)
mem_usage=$(( "$set_size" * "$PAGE_SIZE" )) mem_usage=$((set_size * PAGE_SIZE))
done done
} }
function run { function run {
local arr=() local arr=()
while [[ true ]]; do while :; do
bloat "$BLOAT_ITERATION_TARGET" bloat "$BLOAT_ITERATION_TARGET"
arr+=( "$BLOAT_HOLDER" ) arr+=("${BLOAT_HOLDER[@]}")
sleep 1 sleep 1
done done
} }

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
set -o pipefail set -o pipefail
systemd-analyze log-level debug systemd-analyze log-level debug
@ -7,14 +7,17 @@ systemd-analyze log-target console
# Loose checks to ensure the environment has the necessary features for systemd-oomd # Loose checks to ensure the environment has the necessary features for systemd-oomd
[[ -e /proc/pressure ]] || echo "no PSI" >>/skipped [[ -e /proc/pressure ]] || echo "no PSI" >>/skipped
cgroup_type=$(stat -fc %T /sys/fs/cgroup/) cgroup_type="$(stat -fc %T /sys/fs/cgroup/)"
if [[ "$cgroup_type" != *"cgroup2"* ]] && [[ "$cgroup_type" != *"0x63677270"* ]]; then if [[ "$cgroup_type" != *"cgroup2"* ]] && [[ "$cgroup_type" != *"0x63677270"* ]]; then
echo "no cgroup2" >>/skipped echo "no cgroup2" >>/skipped
fi fi
if [ ! -f /usr/lib/systemd/systemd-oomd ] && [ ! -f /lib/systemd/systemd-oomd ]; then if [ ! -f /usr/lib/systemd/systemd-oomd ] && [ ! -f /lib/systemd/systemd-oomd ]; then
echo "no oomd" >>/skipped echo "no oomd" >>/skipped
fi fi
[[ -e /skipped ]] && exit 0 || true
if [[ -e /skipped ]]; then
exit 0
fi
rm -rf /etc/systemd/system/testsuite-55-testbloat.service.d rm -rf /etc/systemd/system/testsuite-55-testbloat.service.d
@ -30,7 +33,7 @@ oomctl | grep "Default Memory Pressure Duration: 5s"
# systemd-oomd watches for elevated pressure for 5 seconds before acting. # systemd-oomd watches for elevated pressure for 5 seconds before acting.
# It can take time to build up pressure so either wait 2 minutes or for the service to fail. # It can take time to build up pressure so either wait 2 minutes or for the service to fail.
timeout=$(date -ud "2 minutes" +%s) timeout="$(date -ud "2 minutes" +%s)"
while [[ $(date -u +%s) -le $timeout ]]; do while [[ $(date -u +%s) -le $timeout ]]; do
if ! systemctl status testsuite-55-testbloat.service; then if ! systemctl status testsuite-55-testbloat.service; then
break break
@ -55,8 +58,8 @@ if setfattr -n user.xattr_test -v 1 /sys/fs/cgroup/; then
systemctl start testsuite-55-testmunch.service systemctl start testsuite-55-testmunch.service
systemctl start testsuite-55-testbloat.service systemctl start testsuite-55-testbloat.service
timeout=$(date -ud "2 minutes" +%s) timeout="$(date -ud "2 minutes" +%s)"
while [[ $(date -u +%s) -le $timeout ]]; do while [[ "$(date -u +%s)" -le "$timeout" ]]; do
if ! systemctl status testsuite-55-testmunch.service; then if ! systemctl status testsuite-55-testmunch.service; then
break break
fi fi

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex set -eux
systemd-analyze log-level debug systemd-analyze log-level debug