From caa779abb6da2b98122ae06830062e59531d68bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sat, 9 Jul 2022 17:50:36 +0200 Subject: [PATCH 1/3] man: redefine SUPPORT_END= to mean one day earlier I thought it would be nice to specify the last day of support, because I thought it'd seem more natural. But in practice this doesn't work well, because such a truncated timestamp is usually taken to mean midnight that starts the given date. I.e. 2011-12-13 is a shorthand for 2011-12-13 00:00:00 and not 2011-12-13 23:59:59.999999999999. Let's instead specify that the given date is the first unsupported day, which is meaningful for humans, and let the computer treat it as midnight, which gives consistent interpratation. --- man/os-release.xml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/man/os-release.xml b/man/os-release.xml index fd98be5b7a..c5a53ae7eb 100644 --- a/man/os-release.xml +++ b/man/os-release.xml @@ -355,9 +355,12 @@ The date at which support for this version of the OS ends. (What exactly "lack of support" means varies between vendors, but generally users should assume that updates, including - security fixes, will not be provided.) The value is a date in the format - YYYY-MM-DD, and specifies the last day on which support is - provided. + security fixes, will not be provided.) The value is a date in the ISO 8601 format + YYYY-MM-DD, and specifies the first day on which support is + not provided. + + For example, SUPPORT_END=2001-01-01 means that the system was supported + until the end of the last day of the previous millenium. From 8bf9eb7e6b8ecefe7e1792e545c967e1785cbe96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sat, 9 Jul 2022 17:42:07 +0200 Subject: [PATCH 2/3] man: update the description of taint flags We had a description in README, and an outdated list in the man page. I think we should keep a reference-style list in the man page. The description in README is more free-form. --- README | 4 +- man/org.freedesktop.systemd1.xml | 94 +++++++++++++++++++++++++++----- 2 files changed, 83 insertions(+), 15 deletions(-) diff --git a/README b/README index 566f1253b8..0b9988ce20 100644 --- a/README +++ b/README @@ -359,7 +359,7 @@ WARNINGS and TAINT FLAGS: will break if /usr is on a separate late-mounted partition, many of its dependencies very likely will break sooner or later in one form or another. For example, udev rules tend to refer to binaries in /usr, - binaries that link to libraries in /usr or binaries that refer to data + binaries that link to libraries in /usr, or binaries that refer to data files in /usr. Since these breakages are not always directly visible, systemd will warn about this. Such setups are not really supported by the basic set of Linux OS components. Taint flag 'split-usr' will be @@ -393,6 +393,8 @@ WARNINGS and TAINT FLAGS: busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager Tainted + See org.freedesktop.systemd1(5) for more information. + VALGRIND: To run systemd under valgrind, compile with meson option -Dvalgrind=true and have valgrind development headers installed diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index 7974833554..6a532def96 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -1494,21 +1494,87 @@ node /org/freedesktop/systemd1 { it is not part of the public API. Features encodes the features that have been enabled and disabled for this - build. Enabled options are prefixed with +, disabled options with -. + build. Enabled options are prefixed with +, disabled options with + -. - Tainted encodes a couple of taint flags as a colon-separated list. When - systemd detects it is running on a system with certain problems, it will set an appropriate taint - flag. Taints may be used to lower the chance of bogus bug reports. The following taints are currently - known: split-usr, mtab-not-symlink, - cgroups-missing, local-hwclock. split-usr is - set if /usr/ is not pre-mounted when systemd is first invoked. See - - Booting Without /usr is Broken - for details why this is bad. mtab-not-symlink indicates that - /etc/mtab is not a symlink to /proc/self/mounts as - required. cgroups-missing indicates that control groups have not been enabled in the - kernel. local-hwclock indicates that the local RTC is configured to be in local time - rather than UTC. + Tainted encodes taint flags as a colon-separated list. When systemd detects it + is running on a system with a certain problem, it will set an appropriate taint flag. Taints may be + used to lower the chance of bogus bug reports. The following taints are currently known: + + + + split-usr + + /usr/ was not available when systemd was first invoked. It + must either be part of the root file system, or it must be mounted before + systemd is invoked. See + + Booting Without /usr is Broken for details why this is bad. + + + + + unmerged-usr + + /bin, /sbin and + /lib* are not symlinks to their counterparts under /usr/. + For more information on this issue consult + + The Case for the /usr Merge + . + + + + + cgroups-missing + + Support for cgroups is unavailable. + + + + cgroupsv1 + + The system is using the old cgroup hierarchy. + + + + local-hwclock + + The local hardware clock (RTC) is configured to be in local time rather than + UTC. + + + + old-kernel + + The system is running a kernel version that is older than the minimum supported by + this version of systemd. + + + + var-run-bad + + /run/ does not exist or /var/run is not a + symlink to /run/. + + + + overflowuid-not-65534 + overflowgid-not-65534 + + The kernel overflow UID or GID have a value other than 65534. + + + + short-uid-range + short-gid-range + + The UID or GID range assigned to the running systemd instance covers less than + 0…65534. + + + + FirmwareTimestamp, FirmwareTimestampMonotonic, LoaderTimestamp, LoaderTimestampMonotonic, From 4bd035153b1fc11449a7b92e3f7e3554b85404bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sat, 9 Jul 2022 18:00:33 +0200 Subject: [PATCH 3/3] manager: add taint flag "support-ended" In the welcome line, use NAME= as the fallback for PRETTY_NAME=. PRETTY_NAME= doesn't have to be set, but NAME= should. Example output: --- Welcome to Fedora Linux 37 (Rawhide Prerelease)! [ !! ] This OS version (Fedora Linux 37 (Rawhide Prerelease)) is past its end-of-support date (1999-01-01) Queued start job for default target graphical.target. [ OK ] Created slice system-getty.slice. --- --- man/org.freedesktop.systemd1.xml | 9 ++++++ src/basic/os-util.c | 35 +++++++++++++++++++++ src/basic/os-util.h | 2 ++ src/core/main.c | 53 +++++++++++++++++++++----------- src/core/manager.c | 6 +++- src/test/test-os-util.c | 14 +++++++++ 6 files changed, 100 insertions(+), 19 deletions(-) diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index 6a532def96..7803cc9cf9 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -1544,6 +1544,15 @@ node /org/freedesktop/systemd1 { UTC. + + support-ended + + The system is running past the end of support declared by the vendor. See the + description of SUPPORT_END= in + os-release5. + + + old-kernel diff --git a/src/basic/os-util.c b/src/basic/os-util.c index 880fb7e6bb..96ba683276 100644 --- a/src/basic/os-util.c +++ b/src/basic/os-util.c @@ -317,3 +317,38 @@ int load_extension_release_pairs(const char *root, const char *extension, char * return load_env_file_pairs(f, p, ret); } + +int os_release_support_ended(const char *support_end, bool quiet) { + _cleanup_free_ char *_support_end_alloc = NULL; + int r; + + if (!support_end) { + /* If the caller has the variably handy, they can pass it in. If not, we'll read it + * ourselves. */ + + r = parse_os_release(NULL, + "SUPPORT_END", &_support_end_alloc); + if (r < 0) + return log_full_errno((r == -ENOENT || quiet) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to read os-release file, ignoring: %m"); + if (!_support_end_alloc) + return false; /* no end date defined */ + + support_end = _support_end_alloc; + } + + struct tm tm = {}; + + const char *k = strptime(support_end, "%Y-%m-%d", &tm); + if (!k || *k) + return log_full_errno(quiet ? LOG_DEBUG : LOG_WARNING, SYNTHETIC_ERRNO(EINVAL), + "Failed to parse SUPPORT_END= in os-release file, ignoring: %m"); + + time_t eol = mktime(&tm); + if (eol == (time_t) -1) + return log_full_errno(quiet ? LOG_DEBUG : LOG_WARNING, SYNTHETIC_ERRNO(EINVAL), + "Failed to convert SUPPORT_END= in os-release file, ignoring: %m"); + + usec_t ts = now(CLOCK_REALTIME); + return DIV_ROUND_UP(ts, USEC_PER_SEC) > (usec_t) eol; +} diff --git a/src/basic/os-util.h b/src/basic/os-util.h index 271b35fa4e..6883ceaf98 100644 --- a/src/basic/os-util.h +++ b/src/basic/os-util.h @@ -31,3 +31,5 @@ int _parse_os_release(const char *root, ...) _sentinel_; int load_extension_release_pairs(const char *root, const char *extension, char ***ret); int load_os_release_pairs(const char *root, char ***ret); int load_os_release_pairs_with_prefix(const char *root, const char *prefix, char ***ret); + +int os_release_support_ended(const char *support_end, bool quiet); diff --git a/src/core/main.c b/src/core/main.c index 94c757e21e..aee66051db 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1312,29 +1312,46 @@ static int enforce_syscall_archs(Set *archs) { return 0; } -static int status_welcome(void) { - _cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL; +static int os_release_status(void) { + _cleanup_free_ char *pretty_name = NULL, *name = NULL, *version = NULL, + *ansi_color = NULL, *support_end = NULL; int r; - if (!show_status_on(arg_show_status)) - return 0; - r = parse_os_release(NULL, "PRETTY_NAME", &pretty_name, - "ANSI_COLOR", &ansi_color); + "NAME", &name, + "VERSION", &version, + "ANSI_COLOR", &ansi_color, + "SUPPORT_END", &support_end); if (r < 0) - log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, - "Failed to read os-release file, ignoring: %m"); + return log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, + "Failed to read os-release file, ignoring: %m"); - if (log_get_show_color()) - return status_printf(NULL, 0, - "\nWelcome to \x1B[%sm%s\x1B[0m!\n", - isempty(ansi_color) ? "1" : ansi_color, - isempty(pretty_name) ? "Linux" : pretty_name); - else - return status_printf(NULL, 0, - "\nWelcome to %s!\n", - isempty(pretty_name) ? "Linux" : pretty_name); + const char *label = empty_to_null(pretty_name) ?: empty_to_null(name) ?: "Linux"; + + if (show_status_on(arg_show_status)) { + if (log_get_show_color()) + status_printf(NULL, 0, + "\nWelcome to \x1B[%sm%s\x1B[0m!\n", + empty_to_null(ansi_color) ?: "1", + label); + else + status_printf(NULL, 0, + "\nWelcome to %s!\n", + label); + } + + if (support_end && os_release_support_ended(support_end, false) > 0) + /* pretty_name may include the version already, so we'll print the version only if we + * have it and we're not using pretty_name. */ + status_printf(ANSI_HIGHLIGHT_RED " !! " ANSI_NORMAL, 0, + "This OS version (%s%s%s) is past its end-of-support date (%s)", + label, + (pretty_name || !version) ? "" : " version ", + (pretty_name || !version) ? "" : version, + support_end); + + return 0; } static int write_container_id(void) { @@ -2100,7 +2117,7 @@ static int initialize_runtime( return r; } - status_welcome(); + (void) os_release_status(); (void) hostname_setup(true); /* Force transient machine-id on first boot. */ machine_id_setup(NULL, first_boot, arg_machine_id, NULL); diff --git a/src/core/manager.c b/src/core/manager.c index 9c0a686b2a..c7598b1e2a 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -61,6 +61,7 @@ #include "manager-serialize.h" #include "memory-util.h" #include "mkdir-label.h" +#include "os-util.h" #include "parse-util.h" #include "path-lookup.h" #include "path-util.h" @@ -4475,7 +4476,7 @@ char* manager_taint_string(const Manager *m) { assert(m); - const char* stage[12] = {}; + const char* stage[13] = {}; size_t n = 0; if (m->taint_usr) @@ -4494,6 +4495,9 @@ char* manager_taint_string(const Manager *m) { if (clock_is_localtime(NULL) > 0) stage[n++] = "local-hwclock"; + if (os_release_support_ended(NULL, true) > 0) + stage[n++] = "support-ended"; + _cleanup_free_ char *destination = NULL; if (readlink_malloc("/var/run", &destination) < 0 || !PATH_IN_SET(destination, "../run", "/run")) diff --git a/src/test/test-os-util.c b/src/test/test-os-util.c index 2cee6470c4..0cfc1e3dbf 100644 --- a/src/test/test-os-util.c +++ b/src/test/test-os-util.c @@ -72,4 +72,18 @@ TEST(load_os_release_pairs) { assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0); } +TEST(os_release_support_ended) { + int r; + + assert_se(os_release_support_ended("1999-01-01", false) == true); + assert_se(os_release_support_ended("2037-12-31", false) == false); + assert_se(os_release_support_ended("-1-1-1", true) == -EINVAL); + + r = os_release_support_ended(NULL, false); + if (r < 0) + log_info_errno(r, "Failed to check host: %m"); + else + log_info_errno(r, "Host is supported: %s", yes_no(!r)); +} + DEFINE_TEST_MAIN(LOG_DEBUG);