1
0
mirror of https://github.com/systemd/systemd synced 2025-11-21 01:34:44 +01:00

Compare commits

...

7 Commits

Author SHA1 Message Date
Antonio Alvarez Feijoo
2fbfbfc5fa test: enable TEST-06-SELINUX in openSUSE
openSUSE switched to SELinux by default for quite some time now, so this test is
also successful.
2025-10-14 17:56:39 +01:00
Miroslav Lichvar
4db925d7da udev: create symlinks for s390 PTP devices
Similarly to the udev rules handling KVM and Hyper-V PTP devices, create
symlinks for the s390-specific STCKE and Physical clocks (supported
since Linux 6.13) to have some stable names that can be specified in
default configurations of PTP/NTP applications.
2025-10-14 18:31:17 +02:00
Lennart Poettering
1170cc4253
timer: rebase the next elapse timestamp only if timer didn't already run (#39296) 2025-10-14 18:30:23 +02:00
Zbigniew Jędrzejewski-Szmek
e63917abe1 core: allow split /usr/local/s?sbin with merged /usr/s?bin
Previously, we used either the fully split path or the fully merged path,
treating "split sbin" as a boolean condition. The idea was that conversion to
to merged bin would be a single event, so we don't need to care about the
details of the transition. But it turns out that some systems may be converted
in disparate steps. In https://bugzilla.redhat.com/show_bug.cgi?id=2400220,
there was a lengthy discussion about a coreos system where
/usr/local/{bin,sbin} were created as separate directories. Since /usr/local is
not part of the packaged system, it might remain split for a longer time. So
check /usr/local/s?bin separately and stop adding /usr/sbin to $PATH if only
/usr/local/s?bin is split. (I don't think it makes sense to handle the reverse
case, i.e. only /usr/s?bin being split, since that should be much rarer.)

Inspired by https://bugzilla.redhat.com/show_bug.cgi?id=2400220.
2025-10-14 18:30:06 +02:00
Frantisek Sumsal
f50e6fd897 mkosi: explicitly pull in libz1 on OpenSUSE
Otherwise it pulls in libz-ng-compat1 which isn't 100% compatible with
libz1, and more importantly it requires an ldconfig drop-in in /etc/
(/etc/ld.so.conf.d/zlib-ng-compat-x86_64.conf) which breaks hermetic-usr
and TEST-07-PID1:

systemd[5582]: /usr/lib/systemd/systemd: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory
2025-10-14 17:29:58 +01:00
Frantisek Sumsal
bdb8e584f4 timer: rebase the next elapse timestamp only if timer didn't already run
The test added in f4c3c107d9be4e922a080fc292ed3889c4e0f4a5 uncovered a
corner case while recalculating the next elapse timestamp of a timer unit
that uses RandomizedDelaySec= during deserialization.

If the scheduled time (without RandomizedDelaySec=) already elapsed,
systemd "rebases" the next elapse timestamp to the time when systemd
first started, to make the RandomizedDelaySec= feature work even at
boot. However, since it was done unconditionally, it always overrode the
next elapse timestamp, which could then cause the final next elapse
timestamp to fall out of the expected window.

With a couple of additional debug logs one of the test fail looks like
this:

[  132.129815] TEST-53-TIMER.sh[384]: + : 'Next elapse timestamp after daemon-reload, try #328'
[  132.129815] TEST-53-TIMER.sh[384]: + systemctl daemon-reload
[  132.136352] systemd[1]: Reload requested from client PID 16399 ('systemctl') (unit TEST-53-TIMER.service)...
[  132.136636] systemd[1]: Reloading...
[  132.446160] systemd[1]: Rebasing next elapse timestamp
[  132.446168] systemd[1]: v->next_elapse: Tue 2025-10-14 00:10:00 CEST
[  132.446170] systemd[1]: rebased: Tue 2025-10-14 00:10:56 CEST
[  132.446172] systemd[1]: v->next_elapse after rebase: Tue 2025-10-14 00:10:56 CEST
[  132.447361] systemd[1]: Reloading finished in 310 ms.
[  132.484041] TEST-53-TIMER.sh[384]: + check_elapse_timestamp
[  132.484041] TEST-53-TIMER.sh[384]: + systemctl status timer-RandomizedDelaySec-16377.timer
[  132.533657] TEST-53-TIMER.sh[16440]: ● timer-RandomizedDelaySec-16377.timer
[  132.533657] TEST-53-TIMER.sh[16440]:      Loaded: loaded (/run/systemd/system/timer-RandomizedDelaySec-16377.timer; static)
[  132.533657] TEST-53-TIMER.sh[16440]:      Active: active (waiting) since Mon 2025-10-13 23:00:00 CEST; 1h 13min ago
[  132.533657] TEST-53-TIMER.sh[16440]:  Invocation: 5555d4f060114a5493ff228013830d17
[  132.533657] TEST-53-TIMER.sh[16440]:     Trigger: Tue 2025-10-14 22:10:04 CEST; 21h left
[  132.533657] TEST-53-TIMER.sh[16440]:    Triggers: ● timer-RandomizedDelaySec-16377.service
[  132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:07 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Changed dead -> waiting
[  132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:07 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Adding 15h 35min 1.230173s random time.
[  132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:07 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Realtime timer elapses at Tue 2025-10-14 15:45:58 CEST.
[  132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:07 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Changed dead -> waiting
[  132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Adding 16h 29min 44.084409s random time.
[  132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Realtime timer elapses at Tue 2025-10-14 16:40:41 CEST.
[  132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Changed dead -> waiting
[  132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Adding 21h 59min 7.955828s random time.
[  132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Realtime timer elapses at Tue 2025-10-14 22:10:04 CEST.
[  132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Changed dead -> waiting
[  132.535386] TEST-53-TIMER.sh[384]: + systemctl show -p InactiveExitTimestamp timer-RandomizedDelaySec-16377.timer
[  132.537727] TEST-53-TIMER.sh[16442]: InactiveExitTimestamp=Mon 2025-10-13 23:00:00 CEST
[  132.540317] TEST-53-TIMER.sh[16444]: ++ systemctl show -P NextElapseUSecRealtime timer-RandomizedDelaySec-16377.timer
[  132.547745] TEST-53-TIMER.sh[384]: + NEXT_ELAPSE_REALTIME='Tue 2025-10-14 22:10:04 CEST'
[  132.548020] TEST-53-TIMER.sh[16445]: ++ date '--date=Tue 2025-10-14 22:10:04 CEST' +%s
[  132.550218] TEST-53-TIMER.sh[384]: + NEXT_ELAPSE_REALTIME_S=1760472604
[  132.550218] TEST-53-TIMER.sh[384]: + : 'Next elapse timestamp should be Tue 2025-10-14 00:10:00 CEST <= Tue 2025-10-14 22:10:04 CEST <= Tue 2025-10-14 22:10:00 CEST'
[  132.550218] TEST-53-TIMER.sh[384]: + assert_ge 1760472604 1760393400
[  132.550555] TEST-53-TIMER.sh[16446]: + set +ex
[  132.550702] TEST-53-TIMER.sh[384]: + assert_le 1760472604 1760472600
[  132.550832] TEST-53-TIMER.sh[16447]: + set +ex
[  132.551091] TEST-53-TIMER.sh[16447]: FAIL: '1760472604' > '1760472600'

Here the original next elapse timestamp was Tue 2025-10-14 00:10:00 CEST
as expected, but it was overridden by the rebased timestamp:
Tue 2025-10-14 00:10:56 CEST. And when a new randomized delay was added
to it (21h 59min 7.955828s) the final next elapse timestamp fell out of
the expected window, i.e. Tue 2025-10-14 00:10:00 (scheduled time) <
Tue 2025-10-14 22:10:04 CEST (rebased elapse timestamp + randomized
delay) < Tue 2025-10-14 22:10:00 CEST (scheduled time + maximum from
RandomizedDelaySec=, i.e. 22h).

By limiting the timestamp rebase only the case where the unit hasn't
already run should prevent this from happening during daemon-reload.
2025-10-14 16:12:10 +02:00
Frantisek Sumsal
62ca845ac7 test: format the min/max timestamps in "systemd" style
Before:
  Next elapse timestamp should be Sun Oct 12 00:10:00 UTC 2025 <= Sun 2025-10-12 05:43:04 UTC <= Sun Oct 12 22:10:00 UTC

After:
  Next elapse timestamp should be Tue 2025-10-14 00:10:00 CEST <= Tue 2025-10-14 19:39:11 CEST <= Tue 2025-10-14 22:10:00 CEST
2025-10-13 17:35:02 +02:00
9 changed files with 61 additions and 42 deletions

View File

@ -137,7 +137,7 @@ jobs:
sanitizers: ""
llvm: 0
cflags: "-Og"
relabel: no
relabel: yes
vm: 0
no_qemu: 0
no_kvm: 0

View File

@ -61,6 +61,7 @@ Packages=
libdw-devel
libdw1
libtss2-tcti-device0
libz1
man
multipath-tools
ncat

View File

@ -34,6 +34,8 @@ SUBSYSTEM=="net", IMPORT{builtin}="net_driver"
SUBSYSTEM=="ptp", GROUP="clock", MODE="0660"
SUBSYSTEM=="ptp", ATTR{clock_name}=="KVM virtual PTP", SYMLINK+="ptp_kvm"
SUBSYSTEM=="ptp", ATTR{clock_name}=="hyperv", SYMLINK+="ptp_hyperv"
SUBSYSTEM=="ptp", ATTR{clock_name}=="s390 Physical Clock", SYMLINK+="ptp_s390_physical"
SUBSYSTEM=="ptp", ATTR{clock_name}=="s390 STCKE Clock", SYMLINK+="ptp_s390_stcke"
ACTION!="add", GOTO="default_end"

View File

@ -1518,30 +1518,40 @@ int path_glob_can_match(const char *pattern, const char *prefix, char **ret) {
return false;
}
const char* default_PATH(void) {
#if HAVE_SPLIT_BIN
static int split = -1;
static bool dir_is_split(const char *a, const char *b) {
int r;
/* Check whether /usr/sbin is not a symlink and return the appropriate $PATH.
* On error fall back to the safe value with both directories as configured */
if (split < 0)
STRV_FOREACH_PAIR(bin, sbin, STRV_MAKE("/usr/bin", "/usr/sbin",
"/usr/local/bin", "/usr/local/sbin")) {
r = inode_same(*bin, *sbin, AT_NO_AUTOMOUNT);
if (r > 0 || r == -ENOENT)
continue;
if (r < 0)
log_debug_errno(r, "Failed to compare \"%s\" and \"%s\", using compat $PATH: %m",
*bin, *sbin);
split = true;
break;
}
if (split < 0)
split = false;
if (split)
return DEFAULT_PATH_WITH_SBIN;
#endif
return DEFAULT_PATH_WITHOUT_SBIN;
r = inode_same(a, b, AT_NO_AUTOMOUNT);
if (r < 0 && r != -ENOENT) {
log_debug_errno(r, "Failed to compare \"%s\" and \"%s\", assuming split directories: %m", a, b);
return true;
}
return r == 0;
}
#endif
const char* default_PATH(void) {
#if HAVE_SPLIT_BIN
static const char *default_path = NULL;
/* Return one of the three sets of paths:
* a) split /usr/s?bin, /usr/local/sbin doesn't matter.
* b) merged /usr/s?bin, /usr/sbin is a symlink, but /usr/local/sbin is not,
* c) fully merged, neither /usr/sbin nor /usr/local/sbin are symlinks,
*
* On error the fallback to the safe value with both directories as configured is returned.
*/
if (default_path)
return default_path;
if (dir_is_split("/usr/sbin", "/usr/bin"))
return (default_path = DEFAULT_PATH_WITH_FULL_SBIN); /* a */
if (dir_is_split("/usr/local/sbin", "/usr/local/bin"))
return (default_path = DEFAULT_PATH_WITH_LOCAL_SBIN); /* b */
return (default_path = DEFAULT_PATH_WITHOUT_SBIN); /* c */
#else
return DEFAULT_PATH_WITHOUT_SBIN;
#endif
}

View File

@ -9,10 +9,11 @@
#define PATH_MERGED_BIN(x) x "bin"
#define PATH_MERGED_BIN_NULSTR(x) x "bin\0"
#define DEFAULT_PATH_WITH_SBIN PATH_SPLIT_BIN("/usr/local/") ":" PATH_SPLIT_BIN("/usr/")
#define DEFAULT_PATH_WITH_FULL_SBIN PATH_SPLIT_BIN("/usr/local/") ":" PATH_SPLIT_BIN("/usr/")
#define DEFAULT_PATH_WITH_LOCAL_SBIN PATH_SPLIT_BIN("/usr/local/") ":" PATH_MERGED_BIN("/usr/")
#define DEFAULT_PATH_WITHOUT_SBIN PATH_MERGED_BIN("/usr/local/") ":" PATH_MERGED_BIN("/usr/")
#define DEFAULT_PATH_COMPAT PATH_SPLIT_BIN("/usr/local/") ":" PATH_SPLIT_BIN("/usr/") ":" PATH_SPLIT_BIN("/")
#define DEFAULT_PATH_COMPAT DEFAULT_PATH_WITH_FULL_SBIN ":" PATH_SPLIT_BIN("/")
const char* default_PATH(void);

View File

@ -392,7 +392,8 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
continue;
if (v->base == TIMER_CALENDAR) {
usec_t b, rebased, random_offset = 0;
bool rebase_after_boot_time = false;
usec_t b, random_offset = 0;
if (t->random_offset_usec != 0)
random_offset = timer_get_fixed_delay_hash(t) % t->random_offset_usec;
@ -417,8 +418,10 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
b = t->last_trigger.realtime;
else if (dual_timestamp_is_set(&UNIT(t)->inactive_exit_timestamp))
b = UNIT(t)->inactive_exit_timestamp.realtime - random_offset;
else
else {
b = ts.realtime - random_offset;
rebase_after_boot_time = true;
}
r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
if (r < 0)
@ -426,14 +429,16 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
v->next_elapse += random_offset;
/* To make the delay due to RandomizedDelaySec= work even at boot, if the scheduled
* time has already passed, set the time when systemd first started as the scheduled
* time. Note that we base this on the monotonic timestamp of the boot, not the
* realtime one, since the wallclock might have been off during boot. */
rebased = map_clock_usec(UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic,
CLOCK_MONOTONIC, CLOCK_REALTIME);
if (v->next_elapse < rebased)
v->next_elapse = rebased;
if (rebase_after_boot_time) {
/* To make the delay due to RandomizedDelaySec= work even at boot, if the scheduled
* time has already passed, set the time when systemd first started as the scheduled
* time. Note that we base this on the monotonic timestamp of the boot, not the
* realtime one, since the wallclock might have been off during boot. */
usec_t rebased = map_clock_usec(UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic,
CLOCK_MONOTONIC, CLOCK_REALTIME);
if (v->next_elapse < rebased)
v->next_elapse = rebased;
}
if (!found_realtime)
t->next_elapse_realtime = v->next_elapse;

View File

@ -445,8 +445,8 @@ def main() -> None:
summary = Summary.get(args)
# Keep list in sync with TEST-06-SELINUX.sh
if args.name == 'TEST-06-SELINUX' and summary.distribution not in ('fedora', 'centos'):
print('Skipping TEST-06-SELINUX, only enabled for Fedora/CentOS', file=sys.stderr)
if args.name == 'TEST-06-SELINUX' and summary.distribution not in ('centos', 'fedora', 'opensuse'):
print('Skipping TEST-06-SELINUX, only enabled for CentOS/Fedora/openSUSE', file=sys.stderr)
exit(77)
if shell and not sys.stdin.isatty():

View File

@ -4,8 +4,8 @@ set -eux
set -o pipefail
. /etc/os-release
if ! [[ "$ID" =~ centos|fedora ]]; then
echo "Skipping because only CentOS and Fedora support SELinux tests" >>/skipped
if ! [[ "$ID" =~ centos|fedora|opensuse ]]; then
echo "Skipping because only CentOS, Fedora and openSUSE support SELinux tests" >>/skipped
exit 77
fi

View File

@ -15,11 +15,11 @@ set -o pipefail
. "$(dirname "$0")"/util.sh
UNIT_NAME="timer-RandomizedDelaySec-$RANDOM"
TARGET_TS="$(date --date="tomorrow 00:10")"
TARGET_TS="$(date --date="tomorrow 00:10" "+%a %Y-%m-%d %H:%M:%S %Z")"
TARGET_TS_S="$(date --date="$TARGET_TS" "+%s")"
# Maximum possible next elapse timestamp: $TARGET_TS (OnCalendar=) + 22 hours (RandomizedDelaySec=)
MAX_NEXT_ELAPSE_REALTIME_S="$((TARGET_TS_S + 22 * 60 * 60))"
MAX_NEXT_ELAPSE_REALTIME="$(date --date="@$MAX_NEXT_ELAPSE_REALTIME_S")"
MAX_NEXT_ELAPSE_REALTIME="$(date --date="@$MAX_NEXT_ELAPSE_REALTIME_S" "+%a %Y-%m-%d %H:%M:%S %Z")"
# Let's make sure to return the date & time back to the original state once we're done with our time
# shenigans. One way to do this would be to use hwclock, but the RTC in VMs can be unreliable or slow to