1
0
mirror of https://github.com/systemd/systemd synced 2025-10-09 21:54:44 +02:00

Compare commits

...

12 Commits

Author SHA1 Message Date
Lennart Poettering
4990780ed0
Merge pull request #19336 from pdmorrow/reloading_restart
core,test: services in reloading state should exit without waiting TimeoutStartSec
2021-04-22 16:39:06 +02:00
Dimitri John Ledkov
a25100488b
Merge pull request #19346 from mihajlov/dhcp_broadcast_l3
network: enable DHCP broadcast flag if required by interface
2021-04-22 14:22:50 +01:00
Luca Boccassi
f1db009d0e
Merge pull request #19390 from poettering/repart-copy-fixes
repart: fix CopyFiles= corner case when copying into root dir of newly formatted fs
2021-04-22 14:06:10 +01:00
Lennart Poettering
7d25c2463f dissect: fix two minor typos in comments 2021-04-22 13:39:01 +01:00
Emil Renner Berthing
a00ff2e1b5 boot/efi: compile on riscv64
This makes systemd-boot compile against the latest gnu-efi which
just added support for riscv64.
2021-04-22 14:37:25 +02:00
Lennart Poettering
c1737506f3 dissect-image: prefer PARTN= uevent property over "partition" sysfs attr
The kernel will send us a PARTN= uevent proprty with partition add
events, let's use it instead of going for the "partition" sysfs attr.
It's less racy that way and there are reports the sysfs attr shows up
after the device, which makes it evern worse.
2021-04-22 14:31:27 +02:00
Peter Morrow
f209d8f50c test: add a test to cover restarting services in reloading state
Cover the case where a service is recovered out of reloading state via
a restart Restart= configuration.

Signed-off-by: Peter Morrow <pemorrow@linux.microsoft.com>
2021-04-22 09:33:37 +01:00
Peter Morrow
bbe19f6884 core: allow services stuck in reloading state to exit
If a service is in reloading state but has exited do not delay
the final exit until the service reload timer expires. Instead allow
the service to exit immediately since we can't expect the service to
ever transition out of reloading state.

For example if a service sent RELOADING=1 but crashed before it could
send READY=1 then it should be restarted if the service had
Restart= configured.

Signed-off-by: Peter Morrow <pemorrow@linux.microsoft.com>
2021-04-22 09:28:50 +01:00
Lennart Poettering
f21a3a82fb repart: don't try to extract directory of root dir when copying directories
It's OK to specify the root dir as target directory when copying
directories. However, in that case path_extract_filename() is going to
fail, because the root dir simply has not filename.

Let's address that by moving the call further down into the loop, when
we made sure that the target dir doesn't exist yet (the root dir always
exists, hence this check is sufficient).

Moreover, in the branch for copying regular files, also move the calls
down, and generate friendly error messages in case people try to
overwrite dirs with regular files (and the root dir is just a special
case of a dir).

Altogether this makes CopyFiles=/some/place:/ work, i.e. copying some
dir on the host into the root dir of the newly created fs. Previously
this would fail with an error about the inability to extract a filename
from "/", needlessly.
2021-04-21 23:30:49 +02:00
Lennart Poettering
e28190673c repart: don't use basename() when we called path_extract_filename() anyway already
We already have the string, use it.
2021-04-21 23:30:46 +02:00
Lennart Poettering
554a2b6493 repart: prefix the correct path with root dir in log output
When we copy files into the freshly formatted file system, the mount
point prefix must be prepended to the *target* path, not the *source*
path. Not just in code but in the log message about it, too.
2021-04-21 23:30:00 +02:00
Viktor Mihajlovski
e70eca9b48 network: enable DHCP broadcast flag if required by interface
Some interfaces require that the DHCPOFFER message is sent via broadcast
if they can't receive unicast messages before they've been configured
with an IP address.

E.g., s390 ccwgroup network interfaces operating in layer3 mode face
this limitation. This can prevent the interfaces from receiving an
IP address via DHCP, if the have been configured for layer3.

To allow DHCP over such interfaces, we're introducing a new device
property ID_NET_DHCP_BROADCAST which can be set for those.
The networkd DHCP client will check whether this property is set
for an interface, and if so will set the broadcast flag, unless
the network configuration for the interface has an explicit
RequestBroadcast setting.

Besides that, we're adding a udev rule to set this device property
for ccwgroup devices operating in layer3 mode, which is the case
if the ID_NET_DRIVER property is qeth_l3.

Supercedes #18829
2021-04-21 18:11:18 +02:00
15 changed files with 204 additions and 21 deletions

View File

@ -1585,6 +1585,9 @@ if get_option('efi')
elif efi_arch == 'aarch64'
EFI_MACHINE_TYPE_NAME = 'aa64'
gnu_efi_arch = 'aarch64'
elif efi_arch == 'riscv64'
EFI_MACHINE_TYPE_NAME = 'riscv64'
gnu_efi_arch = 'riscv64'
else
EFI_MACHINE_TYPE_NAME = ''
gnu_efi_arch = ''

14
rules.d/81-net-dhcp.rules Normal file
View File

@ -0,0 +1,14 @@
# do not edit this file, it will be overwritten on update
ACTION=="remove", GOTO="net_dhcp_end"
SUBSYSTEM!="net", GOTO="net_dhcp_end"
# Network interfaces requiring DHCPOFFER messages to be broadcast
# must set ID_NET_DHCP_BROADCAST to "1". This property will be
# checked by the networkd DHCP4 client to set the DHCP option
# s390 ccwgroup interfaces in layer3 mode need broadcast DHCPOFFER
# using the link driver to detect this condition
ENV{ID_NET_DRIVER}=="qeth_l3", ENV{ID_NET_DHCP_BROADCAST}="1"
LABEL="net_dhcp_end"

View File

@ -26,6 +26,7 @@ rules = files('''
75-probe_mtd.rules
78-sound-card.rules
80-net-setup-link.rules
81-net-dhcp.rules
'''.split())
if conf.get('HAVE_KMOD') == 1

View File

@ -190,9 +190,9 @@ if have_gnu_efi
'-znocombreloc',
'-L', efi_libdir,
efi_crt0]
if efi_arch == 'aarch64' or efi_arch == 'arm'
# Aarch64 and ARM32 don't have an EFI capable objcopy. Use 'binary'
# instead, and add required symbols manually.
if efi_arch == 'aarch64' or efi_arch == 'arm' or efi_arch == 'riscv64'
# Aarch64, ARM32 and 64bit RISC-V don't have an EFI capable objcopy.
# Use 'binary' instead, and add required symbols manually.
efi_ldflags += ['--defsym=EFI_SUBSYSTEM=0xa']
efi_format = ['-O', 'binary']
else

View File

@ -3474,6 +3474,15 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
case SERVICE_START_POST:
case SERVICE_RELOAD:
/* If neither main nor control processes are running then
* the current state can never exit cleanly, hence immediately
* terminate the service. */
if (control_pid_good(s) <= 0)
service_enter_stop(s, f);
/* Otherwise need to wait untill the operation is done. */
break;
case SERVICE_STOP:
/* Need to wait until the operation is
* done */

View File

@ -1318,6 +1318,30 @@ static int dhcp4_set_request_address(Link *link) {
return sd_dhcp_client_set_request_address(link->dhcp_client, &a->in_addr.in);
}
static bool link_needs_dhcp_broadcast(Link *link) {
const char *val;
int r;
assert(link);
assert(link->network);
/* Return the setting in DHCP[4].RequestBroadcast if specified. Otherwise return the device property
* ID_NET_DHCP_BROADCAST setting, which may be set for interfaces requiring that the DHCPOFFER message
* is being broadcast because they can't handle unicast messages while not fully configured.
* If neither is set or a failure occurs, return false, which is the default for this flag.
*/
r = link->network->dhcp_broadcast;
if (r < 0 && link->sd_device && sd_device_get_property_value(link->sd_device, "ID_NET_DHCP_BROADCAST", &val) >= 0) {
r = parse_boolean(val);
if (r < 0)
log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to parse ID_NET_DHCP_BROADCAST, ignoring: %m");
else
log_link_debug(link, "DHCP4 CLIENT: Detected ID_NET_DHCP_BROADCAST='%d'.", r);
}
return r == true;
}
int dhcp4_configure(Link *link) {
sd_dhcp_option *send_option;
void *request_options;
@ -1359,7 +1383,7 @@ int dhcp4_configure(Link *link) {
if (r < 0)
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set callback: %m");
r = sd_dhcp_client_set_request_broadcast(link->dhcp_client, link->network->dhcp_broadcast);
r = sd_dhcp_client_set_request_broadcast(link->dhcp_client, link_needs_dhcp_broadcast(link));
if (r < 0)
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for broadcast: %m");

View File

@ -207,7 +207,7 @@ DHCPv4.RequestOptions, config_parse_dhcp_request_options,
DHCPv4.Anonymize, config_parse_bool, 0, offsetof(Network, dhcp_anonymize)
DHCPv4.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_send_hostname)
DHCPv4.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp_hostname)
DHCPv4.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast)
DHCPv4.RequestBroadcast, config_parse_tristate, 0, offsetof(Network, dhcp_broadcast)
DHCPv4.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
DHCPv4.MUDURL, config_parse_dhcp_mud_url, 0, 0
DHCPv4.MaxAttempts, config_parse_dhcp_max_attempts, 0, 0
@ -481,7 +481,7 @@ DHCP.UseRoutes, config_parse_bool,
DHCP.Anonymize, config_parse_bool, 0, offsetof(Network, dhcp_anonymize)
DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_send_hostname)
DHCP.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp_hostname)
DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast)
DHCP.RequestBroadcast, config_parse_tristate, 0, offsetof(Network, dhcp_broadcast)
DHCP.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical)
DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
DHCP.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET, offsetof(Network, dhcp_user_class)

View File

@ -315,6 +315,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.dhcp_client_identifier = _DHCP_CLIENT_ID_INVALID,
.dhcp_route_table = RT_TABLE_MAIN,
.dhcp_ip_service_type = -1,
.dhcp_broadcast = -1,
.dhcp6_use_address = true,
.dhcp6_use_dns = true,

View File

@ -136,7 +136,7 @@ struct Network {
int dhcp_ip_service_type;
bool dhcp_anonymize;
bool dhcp_send_hostname;
bool dhcp_broadcast;
int dhcp_broadcast;
bool dhcp_use_dns;
bool dhcp_use_dns_set;
bool dhcp_routes_to_dns;

View File

@ -2801,15 +2801,6 @@ static int do_copy_files(Partition *p, const char *fs) {
STRV_FOREACH_PAIR(source, target, p->copy_files) {
_cleanup_close_ int sfd = -1, pfd = -1, tfd = -1;
_cleanup_free_ char *dn = NULL, *fn = NULL;
r = path_extract_directory(*target, &dn);
if (r < 0)
return log_error_errno(r, "Failed to extract directory from '%s': %m", *target);
r = path_extract_filename(*target, &fn);
if (r < 0)
return log_error_errno(r, "Failed to extract filename from '%s': %m", *target);
sfd = chase_symlinks_and_open(*source, arg_root, CHASE_PREFIX_ROOT|CHASE_WARN, O_CLOEXEC|O_NOCTTY, NULL);
if (sfd < 0)
@ -2823,9 +2814,19 @@ static int do_copy_files(Partition *p, const char *fs) {
/* We are looking at a directory */
tfd = chase_symlinks_and_open(*target, fs, CHASE_PREFIX_ROOT|CHASE_WARN, O_RDONLY|O_DIRECTORY|O_CLOEXEC, NULL);
if (tfd < 0) {
_cleanup_free_ char *dn = NULL, *fn = NULL;
if (tfd != -ENOENT)
return log_error_errno(tfd, "Failed to open target directory '%s': %m", *target);
r = path_extract_filename(*target, &fn);
if (r < 0)
return log_error_errno(r, "Failed to extract filename from '%s': %m", *target);
r = path_extract_directory(*target, &dn);
if (r < 0)
return log_error_errno(r, "Failed to extract directory from '%s': %m", *target);
r = mkdir_p_root(fs, dn, UID_INVALID, GID_INVALID, 0755);
if (r < 0)
return log_error_errno(r, "Failed to create parent directory '%s': %m", dn);
@ -2846,10 +2847,23 @@ static int do_copy_files(Partition *p, const char *fs) {
UID_INVALID, GID_INVALID,
COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS);
if (r < 0)
return log_error_errno(r, "Failed to copy %s%s to %s: %m", strempty(arg_root), *source, *target);
return log_error_errno(r, "Failed to copy '%s' to '%s%s': %m", *source, strempty(arg_root), *target);
} else {
_cleanup_free_ char *dn = NULL, *fn = NULL;
/* We are looking at a regular file */
r = path_extract_filename(*target, &fn);
if (r == -EADDRNOTAVAIL || r == O_DIRECTORY)
return log_error_errno(SYNTHETIC_ERRNO(EISDIR),
"Target path '%s' refers to a directory, but source path '%s' refers to regular file, can't copy.", *target, *source);
if (r < 0)
return log_error_errno(r, "Failed to extract filename from '%s': %m", *target);
r = path_extract_directory(*target, &dn);
if (r < 0)
return log_error_errno(r, "Failed to extract directory from '%s': %m", *target);
r = mkdir_p_root(fs, dn, UID_INVALID, GID_INVALID, 0755);
if (r < 0)
return log_error_errno(r, "Failed to create parent directory: %m");
@ -2858,13 +2872,13 @@ static int do_copy_files(Partition *p, const char *fs) {
if (pfd < 0)
return log_error_errno(pfd, "Failed to open parent directory of target: %m");
tfd = openat(pfd, basename(*target), O_CREAT|O_EXCL|O_WRONLY|O_CLOEXEC, 0700);
tfd = openat(pfd, fn, O_CREAT|O_EXCL|O_WRONLY|O_CLOEXEC, 0700);
if (tfd < 0)
return log_error_errno(errno, "Failed to create target file '%s': %m", *target);
r = copy_bytes(sfd, tfd, UINT64_MAX, COPY_REFLINK|COPY_SIGINT);
if (r < 0)
return log_error_errno(r, "Failed to copy '%s%s' to '%s': %m", strempty(arg_root), *source, *target);
return log_error_errno(r, "Failed to copy '%s' to '%s%s': %m", *source, strempty(arg_root), *target);
(void) copy_xattr(sfd, tfd);
(void) copy_access(sfd, tfd);

View File

@ -139,7 +139,11 @@ static int enumerator_for_parent(sd_device *d, sd_device_enumerator **ret) {
return 0;
}
static int device_is_partition(sd_device *d, sd_device *expected_parent, blkid_partition pp) {
static int device_is_partition(
sd_device *d,
sd_device *expected_parent,
blkid_partition pp) {
const char *v, *parent_syspath, *expected_parent_syspath;
blkid_loff_t bsize, bstart;
uint64_t size, start;
@ -174,9 +178,16 @@ static int device_is_partition(sd_device *d, sd_device *expected_parent, blkid_p
if (!path_equal(parent_syspath, expected_parent_syspath))
return false; /* Has a different parent than what we need, not interesting to us */
r = sd_device_get_sysattr_value(d, "partition", &v);
/* On kernel uevents we may find the partition number in the PARTN= field. Let's use that preferably,
* since it's cheaper and more importantly: the sysfs attribute "partition" appears to become
* available late, hence let's use the property instead, which is available at the moment we see the
* uevent. */
r = sd_device_get_property_value(d, "PARTN", &v);
if (r == -ENOENT)
r = sd_device_get_sysattr_value(d, "partition", &v);
if (r < 0)
return r;
r = safe_atoi(v, &partno);
if (r < 0)
return r;

View File

@ -0,0 +1 @@
../TEST-01-BASIC/Makefile

View File

@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -e
TEST_DESCRIPTION="Test auto restart of exited services which are stuck in reloading state"
TEST_NO_QEMU=1
. $TEST_BASE_DIR/test-functions
do_test "$@" 59

View File

@ -0,0 +1,6 @@
[Unit]
Description=TEST-59-RELOADING-RESTART
[Service]
Type=oneshot
ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh

90
test/units/testsuite-59.sh Executable file
View File

@ -0,0 +1,90 @@
#!/usr/bin/env bash
set -eux
set -o pipefail
fail () {
systemd-analyze log-level info
exit 1
}
# Wait for a service to enter a state within a timeout period, if it doesn't
# enter the desired state within the timeout period then this function will
# exit the test case with a non zero exit code.
wait_on_state_or_fail () {
service=$1
expected_state=$2
timeout=$3
state=$(systemctl show "$service" --property=ActiveState --value)
while [ "$state" != "$expected_state" ]; do
if [ "$timeout" = "0" ]; then
fail
fi
timeout=$((timeout - 1))
sleep 1
state=$(systemctl show "$service" --property=ActiveState --value)
done
}
systemd-analyze log-level debug
systemd-analyze log-target console
cat >/run/systemd/system/testservice-fail-59.service <<EOF
[Unit]
Description=TEST-59-RELOADING-RESTART Normal exit
[Service]
Type=notify
ExecStart=/bin/bash -c "systemd-notify --ready; systemd-notify RELOADING=1; sleep 1; exit 1"
EOF
cat >/run/systemd/system/testservice-fail-restart-59.service <<EOF
[Unit]
Description=TEST-59-RELOADING-RESTART Restart=on-failure
[Service]
Type=notify
ExecStart=/bin/bash -c "systemd-notify --ready; systemd-notify RELOADING=1; sleep 1; exit 1"
Restart=on-failure
StartLimitBurst=1
EOF
cat >/run/systemd/system/testservice-abort-restart-59.service <<EOF
[Unit]
Description=TEST-59-RELOADING-RESTART Restart=on-abort
[Service]
Type=notify
ExecStart=/bin/bash -c "systemd-notify --ready; systemd-notify RELOADING=1; sleep 5; exit 1"
Restart=on-abort
EOF
systemctl daemon-reload
# This service sends a RELOADING=1 message then exits before it sends a
# READY=1. Ensure it enters failed state and does not linger in reloading
# state.
systemctl start testservice-fail-59.service
wait_on_state_or_fail "testservice-fail-59.service" "failed" "30"
# This service sends a RELOADING=1 message then exits before it sends a
# READY=1. It should automatically restart on failure. Ensure it enters failed
# state and does not linger in reloading state.
systemctl start testservice-fail-restart-59.service
wait_on_state_or_fail "testservice-fail-restart-59.service" "failed" "30"
# This service sends a RELOADING=1 message then exits before it sends a
# READY=1. It should automatically restart on abort. It will sleep for 5s
# to allow us to send it a SIGABRT. Ensure the service enters the failed state
# and does not linger in reloading state.
systemctl start testservice-abort-restart-59.service
systemctl --signal=SIGABRT kill testservice-abort-restart-59.service
wait_on_state_or_fail "testservice-abort-restart-59.service" "failed" "30"
systemd-analyze log-level info
echo OK >/testok
exit 0