From 02b7005e38db756711cd6463bda34e93cf304c3c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 Jan 2023 12:28:38 +0100 Subject: [PATCH 1/9] tree-wide: unify how we pick OS pretty name to display --- src/analyze/analyze-plot.c | 3 ++- src/basic/os-util.c | 9 +++++++++ src/basic/os-util.h | 2 ++ src/core/main.c | 2 +- src/firstboot/firstboot.c | 5 +++-- src/hostname/hostnamed.c | 7 ++++++- src/journal-remote/journal-gatewayd.c | 9 ++++++--- 7 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/analyze/analyze-plot.c b/src/analyze/analyze-plot.c index 24f4add099..8aca691b3d 100644 --- a/src/analyze/analyze-plot.c +++ b/src/analyze/analyze-plot.c @@ -6,6 +6,7 @@ #include "bus-error.h" #include "bus-map-properties.h" #include "format-table.h" +#include "os-util.h" #include "sort-util.h" #include "version.h" @@ -283,7 +284,7 @@ static int produce_plot_as_svg( svg("%s", pretty_times); if (host) svg("%s %s (%s %s %s) %s %s", - isempty(host->os_pretty_name) ? "Linux" : host->os_pretty_name, + os_release_pretty_name(host->os_pretty_name, NULL), strempty(host->hostname), strempty(host->kernel_name), strempty(host->kernel_release), diff --git a/src/basic/os-util.c b/src/basic/os-util.c index 9c21dc3bdc..7b84dcb702 100644 --- a/src/basic/os-util.c +++ b/src/basic/os-util.c @@ -370,3 +370,12 @@ int os_release_support_ended(const char *support_end, bool quiet) { usec_t ts = now(CLOCK_REALTIME); return DIV_ROUND_UP(ts, USEC_PER_SEC) > (usec_t) eol; } + +const char *os_release_pretty_name(const char *pretty_name, const char *name) { + /* Distills a "pretty" name to show from os-release data. First argument is supposed to be the + * PRETTY_NAME= field, the second one the NAME= field. This function is trivial, of course, and + * exists mostly to ensure we use the same logic wherever possible. */ + + return empty_to_null(pretty_name) ?: + empty_to_null(name) ?: "Linux"; +} diff --git a/src/basic/os-util.h b/src/basic/os-util.h index d22f5ab8e7..1239f6f6b7 100644 --- a/src/basic/os-util.h +++ b/src/basic/os-util.h @@ -33,3 +33,5 @@ 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); + +const char *os_release_pretty_name(const char *pretty_name, const char *name); diff --git a/src/core/main.c b/src/core/main.c index 94055f08de..19e4f235b2 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1371,7 +1371,7 @@ static int os_release_status(void) { return log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to read os-release file, ignoring: %m"); - const char *label = empty_to_null(pretty_name) ?: empty_to_null(name) ?: "Linux"; + const char *label = os_release_pretty_name(pretty_name, name); if (show_status_on(arg_show_status)) { if (log_get_show_color()) diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 651415568d..45bb386da2 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -97,7 +97,7 @@ static bool press_any_key(void) { } static void print_welcome(void) { - _cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL; + _cleanup_free_ char *pretty_name = NULL, *os_name = NULL, *ansi_color = NULL; static bool done = false; const char *pn, *ac; int r; @@ -111,12 +111,13 @@ static void print_welcome(void) { r = parse_os_release( arg_root, "PRETTY_NAME", &pretty_name, + "NAME", &os_name, "ANSI_COLOR", &ansi_color); if (r < 0) log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to read os-release file, ignoring: %m"); - pn = isempty(pretty_name) ? "Linux" : pretty_name; + pn = os_release_pretty_name(pretty_name, os_name); ac = isempty(ansi_color) ? "0" : ansi_color; if (colors_enabled()) diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index a9782de4ff..a17ecd2b9b 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -146,6 +146,7 @@ static void context_read_machine_info(Context *c) { } static void context_read_os_release(Context *c) { + _cleanup_free_ char *os_name = NULL, *os_pretty_name = NULL; struct stat current_stat = {}; int r; @@ -162,12 +163,16 @@ static void context_read_os_release(Context *c) { (UINT64_C(1) << PROP_OS_HOME_URL)); r = parse_os_release(NULL, - "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME], + "PRETTY_NAME", &os_pretty_name, + "NAME", &os_name, "CPE_NAME", &c->data[PROP_OS_CPE_NAME], "HOME_URL", &c->data[PROP_OS_HOME_URL]); if (r < 0 && r != -ENOENT) log_warning_errno(r, "Failed to read os-release file, ignoring: %m"); + if (free_and_strdup(&c->data[PROP_OS_PRETTY_NAME], os_release_pretty_name(os_pretty_name, os_name)) < 0) + log_oom(); + c->etc_os_release_stat = current_stat; } diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index 747e0be743..a792c75cca 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -732,7 +732,7 @@ static int request_handler_machine( _cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL; RequestMeta *m = ASSERT_PTR(connection_cls); int r; - _cleanup_free_ char* hostname = NULL, *os_name = NULL; + _cleanup_free_ char* hostname = NULL, *pretty_name = NULL, *os_name = NULL; uint64_t cutoff_from = 0, cutoff_to = 0, usage = 0; sd_id128_t mid, bid; _cleanup_free_ char *v = NULL, *json = NULL; @@ -763,7 +763,10 @@ static int request_handler_machine( if (r < 0) return mhd_respondf(connection, r, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine disk usage: %m"); - (void) parse_os_release(NULL, "PRETTY_NAME", &os_name); + (void) parse_os_release( + NULL, + "PRETTY_NAME", &pretty_name, + "NAME=", &os_name); (void) get_virtualization(&v); r = asprintf(&json, @@ -778,7 +781,7 @@ static int request_handler_machine( SD_ID128_FORMAT_VAL(mid), SD_ID128_FORMAT_VAL(bid), hostname_cleanup(hostname), - os_name ? os_name : "Linux", + os_release_pretty_name(pretty_name, os_name), v ? v : "bare", usage, cutoff_from, From 856ad0fdb69b3f93656f11568a91c8b7cb66cb79 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 Jan 2023 12:29:54 +0100 Subject: [PATCH 2/9] os-util: determine distro EOL in UTC, not local timezone Presumably vendors establish a global EOL time, hence its better to interpret the date specification everywhere the same, instead of timezone dependent. --- src/basic/os-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/basic/os-util.c b/src/basic/os-util.c index 7b84dcb702..7e79473634 100644 --- a/src/basic/os-util.c +++ b/src/basic/os-util.c @@ -362,7 +362,7 @@ int os_release_support_ended(const char *support_end, bool quiet) { 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); + time_t eol = timegm(&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"); From 3d46a8292ffd9f502a1a8680bf992917ae8932ad Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 Jan 2023 13:12:43 +0100 Subject: [PATCH 3/9] format-table: add new cell type TABLE_TIMESPAN_DAY This is just like TABLE_TIMESPAN_MSEC, but shows time spans in accuracy of days. --- src/shared/format-table.c | 10 ++++++++-- src/shared/format-table.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/shared/format-table.c b/src/shared/format-table.c index fbac0f7498..ee45d4fd9e 100644 --- a/src/shared/format-table.c +++ b/src/shared/format-table.c @@ -300,6 +300,7 @@ static size_t table_data_size(TableDataType type, const void *data) { case TABLE_TIMESTAMP_DATE: case TABLE_TIMESPAN: case TABLE_TIMESPAN_MSEC: + case TABLE_TIMESPAN_DAY: return sizeof(usec_t); case TABLE_SIZE: @@ -898,6 +899,7 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) { case TABLE_TIMESTAMP_DATE: case TABLE_TIMESPAN: case TABLE_TIMESPAN_MSEC: + case TABLE_TIMESPAN_DAY: buffer.usec = va_arg(ap, usec_t); data = &buffer.usec; break; @@ -1307,6 +1309,7 @@ static int cell_data_compare(TableData *a, size_t index_a, TableData *b, size_t case TABLE_TIMESPAN: case TABLE_TIMESPAN_MSEC: + case TABLE_TIMESPAN_DAY: return CMP(a->timespan, b->timespan); case TABLE_SIZE: @@ -1558,7 +1561,8 @@ static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercas } case TABLE_TIMESPAN: - case TABLE_TIMESPAN_MSEC: { + case TABLE_TIMESPAN_MSEC: + case TABLE_TIMESPAN_DAY: { _cleanup_free_ char *p = NULL; p = new(char, FORMAT_TIMESPAN_MAX); @@ -1566,7 +1570,8 @@ static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercas return NULL; if (!format_timespan(p, FORMAT_TIMESPAN_MAX, d->timespan, - d->type == TABLE_TIMESPAN ? 0 : USEC_PER_MSEC)) + d->type == TABLE_TIMESPAN ? 0 : + d->type == TABLE_TIMESPAN_MSEC ? USEC_PER_MSEC : USEC_PER_DAY)) return "-"; d->formatted = TAKE_PTR(p); @@ -2592,6 +2597,7 @@ static int table_data_to_json(TableData *d, JsonVariant **ret) { case TABLE_TIMESPAN: case TABLE_TIMESPAN_MSEC: + case TABLE_TIMESPAN_DAY: if (d->timespan == USEC_INFINITY) return json_variant_new_null(ret); diff --git a/src/shared/format-table.h b/src/shared/format-table.h index 0817846be2..97255f5aef 100644 --- a/src/shared/format-table.h +++ b/src/shared/format-table.h @@ -26,6 +26,7 @@ typedef enum TableDataType { TABLE_TIMESTAMP_DATE, TABLE_TIMESPAN, TABLE_TIMESPAN_MSEC, + TABLE_TIMESPAN_DAY, TABLE_SIZE, TABLE_BPS, TABLE_INT, From 469af08f58049a2a67b9e0289873a7f3300f5609 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 Jan 2023 13:14:26 +0100 Subject: [PATCH 4/9] os-util: when determining support end, don't treat /etc/os-release file as error Instead, let's just treat it as "field unset". --- src/basic/os-util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/basic/os-util.c b/src/basic/os-util.c index 7e79473634..3a2e4f59a6 100644 --- a/src/basic/os-util.c +++ b/src/basic/os-util.c @@ -346,8 +346,8 @@ int os_release_support_ended(const char *support_end, bool quiet) { 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, + if (r < 0 && r != -ENOENT) + return log_full_errno(quiet ? LOG_DEBUG : LOG_WARNING, r, "Failed to read os-release file, ignoring: %m"); if (!_support_end_alloc) return false; /* no end date defined */ From a9bd4b4ed97c7a6b909febe89a9d2be2c78f3f74 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 Jan 2023 13:15:27 +0100 Subject: [PATCH 5/9] os-util: accept SUPPORT_END= with empty string as explicit way to disable concept --- src/basic/os-util.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/basic/os-util.c b/src/basic/os-util.c index 3a2e4f59a6..3b50279a44 100644 --- a/src/basic/os-util.c +++ b/src/basic/os-util.c @@ -349,14 +349,14 @@ int os_release_support_ended(const char *support_end, bool quiet) { if (r < 0 && r != -ENOENT) return log_full_errno(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 = {}; + if (isempty(support_end)) /* An empty string is a explicit way to say "no EOL exists" */ + return false; /* no end date defined */ + 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), From 6bfe9b3b8d9c208d17ba76bc93ae075afef0ae69 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 Jan 2023 13:16:12 +0100 Subject: [PATCH 6/9] os-util: optionally, return EOL time in os_release_support_ended() --- src/basic/os-util.c | 8 +++++--- src/basic/os-util.h | 2 +- src/core/main.c | 2 +- src/core/manager.c | 2 +- src/test/test-os-util.c | 8 ++++---- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/basic/os-util.c b/src/basic/os-util.c index 3b50279a44..37a4ac1fe4 100644 --- a/src/basic/os-util.c +++ b/src/basic/os-util.c @@ -336,7 +336,7 @@ int load_extension_release_pairs(const char *root, const char *extension, bool r return load_env_file_pairs(f, p, ret); } -int os_release_support_ended(const char *support_end, bool quiet) { +int os_release_support_ended(const char *support_end, bool quiet, usec_t *ret_eol) { _cleanup_free_ char *_support_end_alloc = NULL; int r; @@ -367,8 +367,10 @@ int os_release_support_ended(const char *support_end, bool quiet) { 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; + if (ret_eol) + *ret_eol = eol * USEC_PER_SEC; + + return DIV_ROUND_UP(now(CLOCK_REALTIME), USEC_PER_SEC) > (usec_t) eol; } const char *os_release_pretty_name(const char *pretty_name, const char *name) { diff --git a/src/basic/os-util.h b/src/basic/os-util.h index 1239f6f6b7..a6b121ec43 100644 --- a/src/basic/os-util.h +++ b/src/basic/os-util.h @@ -32,6 +32,6 @@ int load_extension_release_pairs(const char *root, const char *extension, bool r 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); +int os_release_support_ended(const char *support_end, bool quiet, usec_t *ret_eol); const char *os_release_pretty_name(const char *pretty_name, const char *name); diff --git a/src/core/main.c b/src/core/main.c index 19e4f235b2..a7cdc8d631 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1385,7 +1385,7 @@ static int os_release_status(void) { label); } - if (support_end && os_release_support_ended(support_end, false) > 0) + if (support_end && os_release_support_ended(support_end, /* quiet */ false, NULL) > 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, diff --git a/src/core/manager.c b/src/core/manager.c index f8576cca1a..d39e917134 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -4547,7 +4547,7 @@ 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) + if (os_release_support_ended(NULL, /* quiet= */ true, NULL) > 0) stage[n++] = "support-ended"; _cleanup_free_ char *destination = NULL; diff --git a/src/test/test-os-util.c b/src/test/test-os-util.c index 0cfc1e3dbf..bc9e3ec91b 100644 --- a/src/test/test-os-util.c +++ b/src/test/test-os-util.c @@ -75,11 +75,11 @@ TEST(load_os_release_pairs) { 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); + assert_se(os_release_support_ended("1999-01-01", false, NULL) == true); + assert_se(os_release_support_ended("2037-12-31", false, NULL) == false); + assert_se(os_release_support_ended("-1-1-1", true, NULL) == -EINVAL); - r = os_release_support_ended(NULL, false); + r = os_release_support_ended(NULL, false, NULL); if (r < 0) log_info_errno(r, "Failed to check host: %m"); else From b563d5ce6f365955722446d67e58398b130f8052 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 Jan 2023 13:16:52 +0100 Subject: [PATCH 7/9] hostnamed: expose support end timestamp as property on the bus --- man/org.freedesktop.hostname1.xml | 6 +++++ src/hostname/hostnamed.c | 38 +++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/man/org.freedesktop.hostname1.xml b/man/org.freedesktop.hostname1.xml index be36d8fc7e..7cad9a7624 100644 --- a/man/org.freedesktop.hostname1.xml +++ b/man/org.freedesktop.hostname1.xml @@ -82,6 +82,8 @@ node /org/freedesktop/hostname1 { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s OperatingSystemCPEName = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly t OperatingSystemSupportEnd = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s HomeURL = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s HardwareVendor = '...'; @@ -102,6 +104,8 @@ node /org/freedesktop/hostname1 { + + @@ -166,6 +170,8 @@ node /org/freedesktop/hostname1 { + + diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index a17ecd2b9b..36ab0148b9 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -59,6 +59,7 @@ typedef enum { PROP_OS_PRETTY_NAME, PROP_OS_CPE_NAME, PROP_OS_HOME_URL, + PROP_OS_SUPPORT_END, _PROP_MAX, _PROP_INVALID = -EINVAL, } HostProperty; @@ -160,13 +161,15 @@ static void context_read_os_release(Context *c) { context_reset(c, (UINT64_C(1) << PROP_OS_PRETTY_NAME) | (UINT64_C(1) << PROP_OS_CPE_NAME) | - (UINT64_C(1) << PROP_OS_HOME_URL)); + (UINT64_C(1) << PROP_OS_HOME_URL) | + (UINT64_C(1) << PROP_OS_SUPPORT_END)); r = parse_os_release(NULL, "PRETTY_NAME", &os_pretty_name, - "NAME", &os_name, - "CPE_NAME", &c->data[PROP_OS_CPE_NAME], - "HOME_URL", &c->data[PROP_OS_HOME_URL]); + "NAME", &os_name, + "CPE_NAME", &c->data[PROP_OS_CPE_NAME], + "HOME_URL", &c->data[PROP_OS_HOME_URL], + "SUPPORT_END", &c->data[PROP_OS_SUPPORT_END]); if (r < 0 && r != -ENOENT) log_warning_errno(r, "Failed to read os-release file, ignoring: %m"); @@ -886,6 +889,26 @@ static int property_get_os_release_field( return sd_bus_message_append(reply, "s", *(char**) userdata); } +static int property_get_os_support_end( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Context *c = userdata; + usec_t eol = USEC_INFINITY; + + context_read_os_release(c); + + if (c->data[PROP_OS_SUPPORT_END]) + (void) os_release_support_ended(c->data[PROP_OS_SUPPORT_END], /* quiet= */ false, &eol); + + return sd_bus_message_append(reply, "t", eol); +} + static int property_get_icon_name( sd_bus *bus, const char *path, @@ -1251,7 +1274,7 @@ static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *erro _cleanup_free_ char *hn = NULL, *dhn = NULL, *in = NULL, *text = NULL, *chassis = NULL, *vendor = NULL, *model = NULL, *serial = NULL, *firmware_version = NULL, *firmware_vendor = NULL; - usec_t firmware_date = USEC_INFINITY; + usec_t firmware_date = USEC_INFINITY, eol = USEC_INFINITY; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; sd_id128_t product_uuid = SD_ID128_NULL; @@ -1318,6 +1341,9 @@ static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *erro (void) get_firmware_vendor(&firmware_vendor); (void) get_firmware_date(&firmware_date); + if (c->data[PROP_OS_SUPPORT_END]) + (void) os_release_support_ended(c->data[PROP_OS_SUPPORT_END], /* quiet= */ false, &eol); + r = json_build(&v, JSON_BUILD_OBJECT( JSON_BUILD_PAIR("Hostname", JSON_BUILD_STRING(hn)), JSON_BUILD_PAIR("StaticHostname", JSON_BUILD_STRING(c->data[PROP_STATIC_HOSTNAME])), @@ -1334,6 +1360,7 @@ static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *erro JSON_BUILD_PAIR("OperatingSystemPrettyName", JSON_BUILD_STRING(c->data[PROP_OS_PRETTY_NAME])), JSON_BUILD_PAIR("OperatingSystemCPEName", JSON_BUILD_STRING(c->data[PROP_OS_CPE_NAME])), JSON_BUILD_PAIR("OperatingSystemHomeURL", JSON_BUILD_STRING(c->data[PROP_OS_HOME_URL])), + JSON_BUILD_PAIR_FINITE_USEC("OperatingSystemSupportEnd", eol), JSON_BUILD_PAIR("HardwareVendor", JSON_BUILD_STRING(vendor ?: c->data[PROP_HARDWARE_VENDOR])), JSON_BUILD_PAIR("HardwareModel", JSON_BUILD_STRING(model ?: c->data[PROP_HARDWARE_MODEL])), JSON_BUILD_PAIR("HardwareSerial", JSON_BUILD_STRING(serial)), @@ -1377,6 +1404,7 @@ static const sd_bus_vtable hostname_vtable[] = { SD_BUS_PROPERTY("KernelVersion", "s", property_get_uname_field, offsetof(struct utsname, version), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("OperatingSystemCPEName", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("OperatingSystemSupportEnd", "t", property_get_os_support_end, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("HomeURL", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_HOME_URL, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("HardwareVendor", "s", property_get_hardware_vendor, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("HardwareModel", "s", property_get_hardware_model, 0, SD_BUS_VTABLE_PROPERTY_CONST), From 2b72626ee520d911337158b9d604db28534e8de8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 Jan 2023 13:17:21 +0100 Subject: [PATCH 8/9] hostnamectl: show support and among output --- src/hostname/hostnamectl.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c index c77e2e8fd9..4e30053392 100644 --- a/src/hostname/hostnamectl.c +++ b/src/hostname/hostnamectl.c @@ -47,6 +47,7 @@ typedef struct StatusInfo { const char *kernel_release; const char *os_pretty_name; const char *os_cpe_name; + usec_t os_support_end; const char *virtualization; const char *architecture; const char *home_url; @@ -76,6 +77,23 @@ static const char* chassis_string_to_glyph(const char *chassis) { return NULL; } +static const char *os_support_end_color(usec_t n, usec_t eol) { + usec_t left; + + /* If the end of support is over, color output in red. If only a month is left, color output in + * yellow. If more than a year is left, color green. In between just show in regular color. */ + + if (n >= eol) + return ANSI_HIGHLIGHT_RED; + left = eol - n; + if (left < USEC_PER_MONTH) + return ANSI_HIGHLIGHT_YELLOW; + if (left > USEC_PER_YEAR) + return ANSI_HIGHLIGHT_GREEN; + + return NULL; +} + static int print_status_info(StatusInfo *i) { _cleanup_(table_unrefp) Table *table = NULL; sd_id128_t mid = {}, bid = {}; @@ -198,6 +216,19 @@ static int print_status_info(StatusInfo *i) { return table_log_add_error(r); } + if (i->os_support_end != USEC_INFINITY) { + usec_t n = now(CLOCK_REALTIME); + + r = table_add_many(table, + TABLE_FIELD, "OS Support End", + TABLE_TIMESTAMP_DATE, i->os_support_end, + TABLE_FIELD, n < i->os_support_end ? "OS Support Remaining" : "OS Support Expired", + TABLE_TIMESPAN_DAY, n < i->os_support_end ? i->os_support_end - n : n - i->os_support_end, + TABLE_SET_COLOR, os_support_end_color(n, i->os_support_end)); + if (r < 0) + return table_log_add_error(r); + } + if (!isempty(i->kernel_name) && !isempty(i->kernel_release)) { const char *v; @@ -310,6 +341,7 @@ static int show_all_names(sd_bus *bus) { { "KernelRelease", "s", NULL, offsetof(StatusInfo, kernel_release) }, { "OperatingSystemPrettyName", "s", NULL, offsetof(StatusInfo, os_pretty_name) }, { "OperatingSystemCPEName", "s", NULL, offsetof(StatusInfo, os_cpe_name) }, + { "OperatingSystemSupportEnd", "t", NULL, offsetof(StatusInfo, os_support_end) }, { "HomeURL", "s", NULL, offsetof(StatusInfo, home_url) }, { "HardwareVendor", "s", NULL, offsetof(StatusInfo, hardware_vendor) }, { "HardwareModel", "s", NULL, offsetof(StatusInfo, hardware_model) }, From aa9424cbe80dff1baec4224169e8af08026d2539 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 Jan 2023 13:24:04 +0100 Subject: [PATCH 9/9] update TODO --- TODO | 3 --- 1 file changed, 3 deletions(-) diff --git a/TODO b/TODO index 8de5790422..d01acac57e 100644 --- a/TODO +++ b/TODO @@ -639,9 +639,6 @@ Features: forked-but-not-exec'ed children 4. Add varlink API to run transient units based on provided JSON definitions -* show SUPPORT_END= data in "hostnamectl" output (and thus also expose a prop - for this on dbus) - * Add SUPPORT_END_URL= field to os-release with more *actionable* information what to do if support ended