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..7803cc9cf9 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -1494,21 +1494,96 @@ 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.
+
+
+
+ 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
+
+ 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,
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.
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);