diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 8c776960e1..5dd00af952 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -1792,6 +1792,39 @@ bool in_utc_timezone(void) { return timezone == 0 && daylight == 0; } +int usleep_safe(usec_t usec) { + int r; + + /* usleep() takes useconds_t that is (typically?) uint32_t. Also, usleep() may only support the + * range [0, 1000000]. See usleep(3). Let's override usleep() with clock_nanosleep(). + * + * ⚠️ Note we are not using plain nanosleep() here, since that operates on CLOCK_REALTIME, not + * CLOCK_MONOTONIC! */ + + if (usec == 0) + return 0; + + if (usec == USEC_INFINITY) + return RET_NERRNO(pause()); + + struct timespec t; + timespec_store(&t, usec); + + for (;;) { + struct timespec remaining; + + /* `clock_nanosleep()` does not use `errno`, but returns positive error codes. */ + r = -clock_nanosleep(CLOCK_MONOTONIC, /* flags= */ 0, &t, &remaining); + if (r == -EINTR) { + /* Interrupted. Continue sleeping for the remaining time. */ + t = remaining; + continue; + } + + return r; + } +} + int time_change_fd(void) { /* We only care for the cancellation event, hence we set the timeout to the latest possible value. */ diff --git a/src/basic/time-util.h b/src/basic/time-util.h index 13831fcd51..dc6427d98a 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -213,19 +213,7 @@ static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) { return usec_sub_unsigned(timestamp, (usec_t) delta); } -static inline int usleep_safe(usec_t usec) { - /* usleep() takes useconds_t that is (typically?) uint32_t. Also, usleep() may only support the - * range [0, 1000000]. See usleep(3). Let's override usleep() with clock_nanosleep(). - * - * ⚠️ Note we are not using plain nanosleep() here, since that operates on CLOCK_REALTIME, not - * CLOCK_MONOTONIC! */ - - if (usec == 0) - return 0; - - /* `clock_nanosleep()` does not use `errno`, but returns positive error codes. */ - return -clock_nanosleep(CLOCK_MONOTONIC, 0, TIMESPEC_STORE(usec), NULL); -} +int usleep_safe(usec_t usec); /* The last second we can format is 31. Dec 9999, 1s before midnight, because otherwise we'd enter 5 digit * year territory. However, since we want to stay away from this in all timezones we take one day off. */ diff --git a/src/test/meson.build b/src/test/meson.build index 2366dbaf1c..a21f85c2ec 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -460,6 +460,10 @@ executables += [ libbasic_static, ], }, + test_template + { + 'sources' : files('test-sleep.c'), + 'type' : 'manual', + }, test_template + { 'sources' : files('test-time-util.c'), 'timeout' : 120, diff --git a/src/test/test-sleep.c b/src/test/test-sleep.c new file mode 100644 index 0000000000..90b5cfe2b1 --- /dev/null +++ b/src/test/test-sleep.c @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "log.h" +#include "main-func.h" +#include "time-util.h" + +static int run(int argc, char *argv[]) { + usec_t usec = USEC_INFINITY; + int r; + + if (argc > 1) { + r = parse_sec(argv[1], &usec); + if (r < 0) + return log_error_errno(r, "Failed to parse timespan '%s': %m", argv[1]); + } + + r = usleep_safe(usec); + if (r < 0) + return log_error_errno(r, "Failed to sleep: %m"); + + return 0; +} + +DEFINE_MAIN_FUNCTION(run); diff --git a/test/units/TEST-82-SOFTREBOOT.sh b/test/units/TEST-82-SOFTREBOOT.sh index 378ac2a2a2..03f6b78e57 100755 --- a/test/units/TEST-82-SOFTREBOOT.sh +++ b/test/units/TEST-82-SOFTREBOOT.sh @@ -90,16 +90,12 @@ if [ -f /run/TEST-82-SOFTREBOOT.touch3 ]; then # Check that the surviving services are still around test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive.service)" = "active" - if [[ ! -L $(command -v sleep) ]]; then - test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive-argv.service)" = "active" - fi + test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive-argv.service)" = "active" test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive-sigterm.service)" != "active" test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive.service)" != "active" [[ ! -e /run/credentials/TEST-82-SOFTREBOOT-nosurvive.service ]] - if [[ ! -L $(command -v sleep) ]]; then - assert_eq "$(cat /run/credentials/TEST-82-SOFTREBOOT-survive-argv.service/preserve)" "yay" - fi + assert_eq "$(cat /run/credentials/TEST-82-SOFTREBOOT-survive-argv.service/preserve)" "yay" # There may be huge amount of pending messages in sockets. Processing them may cause journal rotation and # removal of old archived journal files. If a journal file is removed during journalctl reading it, @@ -134,9 +130,7 @@ elif [ -f /run/TEST-82-SOFTREBOOT.touch2 ]; then # Check that the surviving services are still around test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive.service)" = "active" - if [[ ! -L $(command -v sleep) ]]; then - test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive-argv.service)" = "active" - fi + test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive-argv.service)" = "active" test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive-sigterm.service)" != "active" test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive.service)" != "active" @@ -192,9 +186,7 @@ elif [ -f /run/TEST-82-SOFTREBOOT.touch ]; then # Check that the surviving services are still around test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive.service)" = "active" - if [[ ! -L $(command -v sleep) ]]; then - test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive-argv.service)" = "active" - fi + test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive-argv.service)" = "active" test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive-sigterm.service)" != "active" test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive.service)" != "active" @@ -261,7 +253,9 @@ EOF #!/usr/bin/env bash systemd-notify --ready rm "$survive_argv" -exec -a @sleep sleep infinity +# Here, we use our own sleep implementation, to support coreutils built with +# --enable-single-binary=symlinks, in that case we cannot rename COMM of sleep command. +exec -a @sleep /usr/lib/systemd/tests/unit-tests/manual/test-sleep infinity EOF chmod +x "$survive_argv" # This sets DefaultDependencies=no so that they remain running until the very end, and @@ -282,17 +276,15 @@ EOF # soft reboots due to journald being temporarily stopped. # Note, when coreutils is built with --enable-single-binary=symlinks, unfortunately we cannot freely rename # sleep command, hence we cannot test the feature. - if [[ ! -L $(command -v sleep) ]]; then - systemd-run --service-type=notify --unit=TEST-82-SOFTREBOOT-survive-argv.service \ - --property SurviveFinalKillSignal=no \ - --property IgnoreOnIsolate=yes \ - --property DefaultDependencies=no \ - --property After=basic.target \ - --property "Conflicts=reboot.target kexec.target poweroff.target halt.target emergency.target rescue.target" \ - --property "Before=reboot.target kexec.target poweroff.target halt.target emergency.target rescue.target" \ - --property SetCredential=preserve:yay \ - "$survive_argv" - fi + systemd-run --service-type=notify --unit=TEST-82-SOFTREBOOT-survive-argv.service \ + --property SurviveFinalKillSignal=no \ + --property IgnoreOnIsolate=yes \ + --property DefaultDependencies=no \ + --property After=basic.target \ + --property "Conflicts=reboot.target kexec.target poweroff.target halt.target emergency.target rescue.target" \ + --property "Before=reboot.target kexec.target poweroff.target halt.target emergency.target rescue.target" \ + --property SetCredential=preserve:yay \ + "$survive_argv" # shellcheck disable=SC2016 systemd-run --service-type=exec --unit=TEST-82-SOFTREBOOT-survive.service \ --property TemporaryFileSystem="/run /tmp /var" \ diff --git a/test/units/TEST-87-AUX-UTILS-VM.coredump.sh b/test/units/TEST-87-AUX-UTILS-VM.coredump.sh index 1b37197bde..b3f702a2b0 100755 --- a/test/units/TEST-87-AUX-UTILS-VM.coredump.sh +++ b/test/units/TEST-87-AUX-UTILS-VM.coredump.sh @@ -6,11 +6,6 @@ set -o pipefail # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh -if [[ -L $(command -v sleep) ]]; then - # coreutils is built with --enable-single-binary=symlinks, and we cannot rename it. - exit 0 -fi - # Make sure the binary name fits into 15 characters CORE_TEST_BIN="/tmp/test-dump" CORE_TEST_UNPRIV_BIN="/tmp/test-usr-dump" @@ -35,8 +30,8 @@ sysctl kernel.core_pattern | grep systemd-coredump # Prepare "fake" binaries for coredumps, so we can properly exercise # the matching stuff too -cp -vf /bin/sleep "${CORE_TEST_BIN:?}" -cp -vf /bin/sleep "${CORE_TEST_UNPRIV_BIN:?}" +cp -vf /usr/lib/systemd/tests/unit-tests/manual/test-sleep "${CORE_TEST_BIN:?}" +cp -vf /usr/lib/systemd/tests/unit-tests/manual/test-sleep "${CORE_TEST_UNPRIV_BIN:?}" # Simple script that spawns given "fake" binary and then kills it with # given signal cat >"${MAKE_DUMP_SCRIPT:?}" <<\EOF