systemd-252-57

Resolves: RHEL-108555,RHEL-108568,RHEL-108576,RHEL-108584,RHEL-108596,RHEL-108598,RHEL-109096,RHEL-109488,RHEL-111065,RHEL-31756,RHEL-50103
This commit is contained in:
Jan Macku 2025-09-16 08:59:46 +02:00
parent 531076b9fc
commit 2169d2c18c
58 changed files with 4951 additions and 1 deletions

View File

@ -0,0 +1,96 @@
From 3d54c58e3d4c720a9a95a39879b795e7154f0209 Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Fri, 23 Dec 2022 14:14:53 +0100
Subject: [PATCH] Revert "boot: Use EFI_BOOT_MANAGER_POLICY_PROTOCOL to connect
console devices"
This reverts commit b99bf5811850afdb2502ba37251c48348da63c82.
It seems that using this protocol on some firmwares to forcibly
initialize console devices may break handles (already opened file
handles and the device handle itself) that we rely on to access the
boot filesystem, making it impossible to load the selected entry.
It might be possible to get a new handle by querying for the device
handle by using its device path after calling into this protocol, but
this is untested. The firmware might also be so buggy that accessing
devices after using this protocol is impossible.
It seems prudent to revert this for now until some reliable way is found
to initialize console devices without introducing huge boot delays. Any
users on firmware where console devices cannot be accessed would have to
rely on disabling fastboot.
Fixes: #25737, #25846
(cherry picked from commit f151abb0e5fa4f820109eb0541bfdcba319d2b92)
Resolves: RHEL-108596
---
src/boot/efi/console.c | 16 ----------------
src/boot/efi/missing_efi.h | 19 -------------------
2 files changed, 35 deletions(-)
diff --git a/src/boot/efi/console.c b/src/boot/efi/console.c
index 85a76e6e68..3b8b6b2e41 100644
--- a/src/boot/efi/console.c
+++ b/src/boot/efi/console.c
@@ -12,20 +12,6 @@
#define VERTICAL_MAX_OK 1080
#define VIEWPORT_RATIO 10
-static EFI_STATUS console_connect(void) {
- EFI_BOOT_MANAGER_POLICY_PROTOCOL *boot_policy;
- EFI_STATUS err;
-
- /* This should make console devices appear/fully initialize on fastboot firmware. */
-
- err = BS->LocateProtocol(
- &(EFI_GUID) EFI_BOOT_MANAGER_POLICY_PROTOCOL_GUID, NULL, (void **) &boot_policy);
- if (err != EFI_SUCCESS)
- return err;
-
- return boot_policy->ConnectDeviceClass(boot_policy, &(EFI_GUID) EFI_BOOT_MANAGER_POLICY_CONSOLE_GUID);
-}
-
static inline void event_closep(EFI_EVENT *event) {
if (!*event)
return;
@@ -61,8 +47,6 @@ EFI_STATUS console_key_read(uint64_t *key, uint64_t timeout_usec) {
assert(key);
if (!checked) {
- console_connect();
-
/* Get the *first* TextInputEx device.*/
err = BS->LocateProtocol(
MAKE_GUID_PTR(EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL), NULL, (void **) &extraInEx);
diff --git a/src/boot/efi/missing_efi.h b/src/boot/efi/missing_efi.h
index d34dfc3379..3c35a85e46 100644
--- a/src/boot/efi/missing_efi.h
+++ b/src/boot/efi/missing_efi.h
@@ -399,25 +399,6 @@ typedef struct {
} EFI_SHELL_PARAMETERS_PROTOCOL;
#endif
-#ifndef EFI_BOOT_MANAGER_POLICY_PROTOCOL_GUID
-#define EFI_BOOT_MANAGER_POLICY_PROTOCOL_GUID \
- { 0xFEDF8E0C, 0xE147, 0x11E3, { 0x99, 0x03, 0xB8, 0xE8, 0x56, 0x2C, 0xBA, 0xFA } }
-#define EFI_BOOT_MANAGER_POLICY_CONSOLE_GUID \
- { 0xCAB0E94C, 0xE15F, 0x11E3, { 0x91, 0x8D, 0xB8, 0xE8, 0x56, 0x2C, 0xBA, 0xFA } }
-
-typedef struct EFI_BOOT_MANAGER_POLICY_PROTOCOL EFI_BOOT_MANAGER_POLICY_PROTOCOL;
-struct EFI_BOOT_MANAGER_POLICY_PROTOCOL {
- UINT64 Revision;
- EFI_STATUS (EFIAPI *ConnectDevicePath)(
- EFI_BOOT_MANAGER_POLICY_PROTOCOL *This,
- EFI_DEVICE_PATH *DevicePath,
- BOOLEAN Recursive);
- EFI_STATUS (EFIAPI *ConnectDeviceClass)(
- EFI_BOOT_MANAGER_POLICY_PROTOCOL *This,
- EFI_GUID *Class);
-};
-#endif
-
#ifndef EFI_WARN_UNKNOWN_GLYPH
# define EFI_WARN_UNKNOWN_GLYPH 1
#endif

View File

@ -0,0 +1,38 @@
From bcb456e590fd6994a6b38e9b2d89e3ef0417d402 Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Tue, 2 May 2023 19:41:58 +0200
Subject: [PATCH] boot: Use correct memory type for allocations
We were using the wrong memory type when allocating pool memory. This
does not seem to cause a problem on x86, but the kernel will fail to
boot at least on ARM in QEMU.
This is caused by mixing different allocation types which ended up
breaking the kernel or EDK2 during boot services exit. Commit
2f3c3b0bee5534f2338439f04b0aa517479f8b76 appears to fix this boot
failure because it was replacing the gnu-efi xpool_print with xasprintf
thereby unifying the allocation type.
But this same issue can also happen without this fix somehow when the
random-seed logic is in use.
Fixes: #27371
(cherry picked from commit ec232e4abd7aebfec06b4814b30129532b2bcefd)
Resolves: RHEL-108555
---
src/boot/efi/util.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h
index f7452e3cf5..16c9fcc3e1 100644
--- a/src/boot/efi/util.h
+++ b/src/boot/efi/util.h
@@ -47,7 +47,7 @@ static inline void freep(void *p) {
_malloc_ _alloc_(1) _returns_nonnull_ _warn_unused_result_
static inline void *xmalloc(size_t size) {
void *p;
- assert_se(BS->AllocatePool(EfiBootServicesData, size, &p) == EFI_SUCCESS);
+ assert_se(BS->AllocatePool(EfiLoaderData, size, &p) == EFI_SUCCESS);
return p;
}

View File

@ -0,0 +1,33 @@
From 7ee5909a539f7a4a65c35e86404ceecb499c54c5 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 2 Nov 2023 14:20:11 +0900
Subject: [PATCH] meson: /etc/systemd/network is also used by udevd
(cherry picked from commit 6256c65aad2a719ac9054961561bb26e497208ce)
Resolves: RHEL-109096
---
network/meson.build | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/network/meson.build b/network/meson.build
index 4c6de20515..499ea61086 100644
--- a/network/meson.build
+++ b/network/meson.build
@@ -12,11 +12,12 @@ if conf.get('ENABLE_NETWORKD') == 1
'80-wifi-station.network.example',
install_dir : networkdir)
- if install_sysconfdir
- meson.add_install_script('sh', '-c',
- mkdir_p.format(sysconfdir / 'systemd/network'))
- endif
endif
install_data('99-default.link',
install_dir : networkdir)
+
+if install_sysconfdir
+ meson.add_install_script('sh', '-c',
+ mkdir_p.format(sysconfdir / 'systemd/network'))
+endif

View File

@ -0,0 +1,207 @@
From 3b49b68593cbca6ee4e08a34a780fd5b5c3ab9fb Mon Sep 17 00:00:00 2001
From: licunlong <licunlong1@huawei.com>
Date: Thu, 15 Jun 2023 16:28:28 +0800
Subject: [PATCH] sd-bus: make bus_add_match_full accept timeout
(cherry picked from commit bb30e58f644689feaa87d8136d1686b6c3a6f42a)
Related: RHEL-31756
---
src/libsystemd/sd-bus/bus-control.c | 48 +++++++++++++++++++++-------
src/libsystemd/sd-bus/bus-control.h | 4 +--
src/libsystemd/sd-bus/bus-internal.h | 10 ++++++
src/libsystemd/sd-bus/sd-bus.c | 17 ++++++----
4 files changed, 59 insertions(+), 20 deletions(-)
diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c
index d96b7256a1..762656fa74 100644
--- a/src/libsystemd/sd-bus/bus-control.c
+++ b/src/libsystemd/sd-bus/bus-control.c
@@ -803,9 +803,10 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
int bus_add_match_internal(
sd_bus *bus,
const char *match,
+ uint64_t timeout_usec,
uint64_t *ret_counter) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
const char *e;
int r;
@@ -816,16 +817,26 @@ int bus_add_match_internal(
e = append_eavesdrop(bus, match);
- r = sd_bus_call_method(
+ r = sd_bus_message_new_method_call(
bus,
+ &m,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
- "AddMatch",
+ "AddMatch");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "s", e);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_call(
+ bus,
+ m,
+ timeout_usec,
NULL,
- &reply,
- "s",
- e);
+ &reply);
if (r < 0)
return r;
@@ -841,9 +852,12 @@ int bus_add_match_internal_async(
sd_bus_slot **ret_slot,
const char *match,
sd_bus_message_handler_t callback,
- void *userdata) {
+ void *userdata,
+ uint64_t timeout_usec) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
const char *e;
+ int r;
assert(bus);
@@ -852,17 +866,27 @@ int bus_add_match_internal_async(
e = append_eavesdrop(bus, match);
- return sd_bus_call_method_async(
+ r = sd_bus_message_new_method_call(
bus,
- ret_slot,
+ &m,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
- "AddMatch",
+ "AddMatch");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "s", e);
+ if (r < 0)
+ return r;
+
+ return sd_bus_call_async(
+ bus,
+ ret_slot,
+ m,
callback,
userdata,
- "s",
- e);
+ timeout_usec);
}
int bus_remove_match_internal(
diff --git a/src/libsystemd/sd-bus/bus-control.h b/src/libsystemd/sd-bus/bus-control.h
index 8182b9cd63..1cd4fb88d9 100644
--- a/src/libsystemd/sd-bus/bus-control.h
+++ b/src/libsystemd/sd-bus/bus-control.h
@@ -3,7 +3,7 @@
#include "sd-bus.h"
-int bus_add_match_internal(sd_bus *bus, const char *match, uint64_t *ret_counter);
-int bus_add_match_internal_async(sd_bus *bus, sd_bus_slot **ret, const char *match, sd_bus_message_handler_t callback, void *userdata);
+int bus_add_match_internal(sd_bus *bus, const char *match, uint64_t timeout_usec, uint64_t *ret_counter);
+int bus_add_match_internal_async(sd_bus *bus, sd_bus_slot **ret, const char *match, sd_bus_message_handler_t callback, void *userdata, uint64_t timeout_usec);
int bus_remove_match_internal(sd_bus *bus, const char *match);
diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h
index 51673ad1c5..603a53fb10 100644
--- a/src/libsystemd/sd-bus/bus-internal.h
+++ b/src/libsystemd/sd-bus/bus-internal.h
@@ -386,6 +386,16 @@ int bus_attach_inotify_event(sd_bus *b);
void bus_close_inotify_fd(sd_bus *b);
void bus_close_io_fds(sd_bus *b);
+int bus_add_match_full(
+ sd_bus *bus,
+ sd_bus_slot **slot,
+ bool asynchronous,
+ const char *match,
+ sd_bus_message_handler_t callback,
+ sd_bus_message_handler_t install_callback,
+ void *userdata,
+ uint64_t timeout_usec);
+
#define OBJECT_PATH_FOREACH_PREFIX(prefix, path) \
for (char *_slash = ({ strcpy((prefix), (path)); streq((prefix), "/") ? NULL : strrchr((prefix), '/'); }) ; \
_slash && ((_slash[(_slash) == (prefix)] = 0), true); \
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 10efe53a25..b8406f154b 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -3486,14 +3486,15 @@ static int add_match_callback(
return r;
}
-static int bus_add_match_full(
+int bus_add_match_full(
sd_bus *bus,
sd_bus_slot **slot,
bool asynchronous,
const char *match,
sd_bus_message_handler_t callback,
sd_bus_message_handler_t install_callback,
- void *userdata) {
+ void *userdata,
+ uint64_t timeout_usec) {
struct bus_match_component *components = NULL;
unsigned n_components = 0;
@@ -3539,7 +3540,8 @@ static int bus_add_match_full(
&s->match_callback.install_slot,
s->match_callback.match_string,
add_match_callback,
- s);
+ s,
+ timeout_usec);
if (r < 0)
goto finish;
@@ -3549,7 +3551,10 @@ static int bus_add_match_full(
* then make it floating. */
r = sd_bus_slot_set_floating(s->match_callback.install_slot, true);
} else
- r = bus_add_match_internal(bus, s->match_callback.match_string, &s->match_callback.after);
+ r = bus_add_match_internal(bus,
+ s->match_callback.match_string,
+ timeout_usec,
+ &s->match_callback.after);
if (r < 0)
goto finish;
@@ -3580,7 +3585,7 @@ _public_ int sd_bus_add_match(
sd_bus_message_handler_t callback,
void *userdata) {
- return bus_add_match_full(bus, slot, false, match, callback, NULL, userdata);
+ return bus_add_match_full(bus, slot, false, match, callback, NULL, userdata, 0);
}
_public_ int sd_bus_add_match_async(
@@ -3591,7 +3596,7 @@ _public_ int sd_bus_add_match_async(
sd_bus_message_handler_t install_callback,
void *userdata) {
- return bus_add_match_full(bus, slot, true, match, callback, install_callback, userdata);
+ return bus_add_match_full(bus, slot, true, match, callback, install_callback, userdata, 0);
}
bool bus_pid_changed(sd_bus *bus) {

View File

@ -0,0 +1,52 @@
From 1a5720577ae6791ae64795486c5902b7c5aceb6b Mon Sep 17 00:00:00 2001
From: licunlong <licunlong1@huawei.com>
Date: Thu, 15 Jun 2023 10:47:32 +0800
Subject: [PATCH] core/unit: add get_timeout_start_usec in UnitVTable and
define it for service
(cherry picked from commit f5a9d2ee2a849aca1f2d15485d020142ff33cc30)
Related: RHEL-31756
---
src/core/service.c | 6 ++++++
src/core/unit.h | 3 +++
2 files changed, 9 insertions(+)
diff --git a/src/core/service.c b/src/core/service.c
index 433df0afe3..305f3b7170 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -4383,6 +4383,11 @@ static int service_get_timeout(Unit *u, usec_t *timeout) {
return 1;
}
+static usec_t service_get_timeout_start_usec(Unit *u) {
+ Service *s = SERVICE(ASSERT_PTR(u));
+ return s->timeout_start_usec;
+}
+
static bool pick_up_pid_from_bus_name(Service *s) {
assert(s);
@@ -4870,6 +4875,7 @@ const UnitVTable service_vtable = {
.bus_commit_properties = bus_service_commit_properties,
.get_timeout = service_get_timeout,
+ .get_timeout_start_usec = service_get_timeout_start_usec,
.needs_console = service_needs_console,
.exit_status = service_exit_status,
.status_text = service_status_text,
diff --git a/src/core/unit.h b/src/core/unit.h
index 4bb85b55be..fdea76458d 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -713,6 +713,9 @@ typedef struct UnitVTable {
/* Returns the next timeout of a unit */
int (*get_timeout)(Unit *u, usec_t *timeout);
+ /* Returns the start timeout of a unit */
+ usec_t (*get_timeout_start_usec)(Unit *u);
+
/* Returns the main PID if there is any defined, or 0. */
pid_t (*main_pid)(Unit *u);

View File

@ -0,0 +1,99 @@
From 6b2f0e500e6688d1b2d9ad8b9947e03bd58f27a2 Mon Sep 17 00:00:00 2001
From: licunlong <licunlong1@huawei.com>
Date: Wed, 24 May 2023 11:45:31 +0800
Subject: [PATCH] core/unit: increase the NameOwnerChanged/GetNameOwner timeout
to the unit's start timeout
When dbus is overloaded, these messages are easily timedout,
systemd may kill dbus-type service by mistake. This PR
mitigates this problem by increasing the timeout to the
unit's start timeout.
(cherry picked from commit 8df433d7cd268ae96cfe795feaa59f4d3e87b85c)
Related: RHEL-31756
---
src/core/unit.c | 39 ++++++++++++++++++++++++++++++++++-----
1 file changed, 34 insertions(+), 5 deletions(-)
diff --git a/src/core/unit.c b/src/core/unit.c
index 0d65880ac7..dddaeb96f6 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -14,6 +14,7 @@
#include "bpf-foreign.h"
#include "bpf-socket-bind.h"
#include "bus-common-errors.h"
+#include "bus-internal.h"
#include "bus-util.h"
#include "cgroup-setup.h"
#include "cgroup-util.h"
@@ -3539,7 +3540,9 @@ static int get_name_owner_handler(sd_bus_message *message, void *userdata, sd_bu
}
int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
const char *match;
+ usec_t timeout_usec = 0;
int r;
assert(u);
@@ -3549,6 +3552,12 @@ int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
if (u->match_bus_slot || u->get_name_owner_slot)
return -EBUSY;
+ /* NameOwnerChanged and GetNameOwner is used to detect when a service finished starting up. The dbus
+ * call timeout shouldn't be earlier than that. If we couldn't get the start timeout, use the default
+ * value defined above. */
+ if (UNIT_VTABLE(u)->get_timeout_start_usec)
+ timeout_usec = UNIT_VTABLE(u)->get_timeout_start_usec(u);
+
match = strjoina("type='signal',"
"sender='org.freedesktop.DBus',"
"path='/org/freedesktop/DBus',"
@@ -3556,20 +3565,40 @@ int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
"member='NameOwnerChanged',"
"arg0='", name, "'");
- r = sd_bus_add_match_async(bus, &u->match_bus_slot, match, signal_name_owner_changed, NULL, u);
+ r = bus_add_match_full(
+ bus,
+ &u->match_bus_slot,
+ true,
+ match,
+ signal_name_owner_changed,
+ NULL,
+ u,
+ timeout_usec);
if (r < 0)
return r;
- r = sd_bus_call_method_async(
+ r = sd_bus_message_new_method_call(
bus,
- &u->get_name_owner_slot,
+ &m,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
- "GetNameOwner",
+ "GetNameOwner");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "s", name);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_call_async(
+ bus,
+ &u->get_name_owner_slot,
+ m,
get_name_owner_handler,
u,
- "s", name);
+ timeout_usec);
+
if (r < 0) {
u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
return r;

View File

@ -0,0 +1,38 @@
From 14c6c9a0a58a99d66f541cec50a5cc860303ae7e Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Sun, 29 Dec 2024 15:10:53 +0900
Subject: [PATCH] core,sd-bus: drop empty lines between function call and error
check
(cherry picked from commit 7baf4d234a70f136014f9e92f00c078a55c7adba)
Related: RHEL-31756
---
src/core/unit.c | 1 -
src/libsystemd/sd-bus/sd-bus.c | 1 -
2 files changed, 2 deletions(-)
diff --git a/src/core/unit.c b/src/core/unit.c
index dddaeb96f6..5a091b3bc4 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -3598,7 +3598,6 @@ int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
get_name_owner_handler,
u,
timeout_usec);
-
if (r < 0) {
u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
return r;
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index b8406f154b..c2dded43ad 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -3542,7 +3542,6 @@ int bus_add_match_full(
add_match_callback,
s,
timeout_usec);
-
if (r < 0)
goto finish;

View File

@ -0,0 +1,71 @@
From 899e94d72119c5e5f3d0ae75f39abd376bc28b0e Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Sun, 29 Dec 2024 15:50:43 +0900
Subject: [PATCH] core: do not disconnect from bus when failed to install
signal match
If bus_add_match_full() is called without install callback and we failed
to install the signal match e.g. by timeout, then add_match_callback()
will disconnect from the bus.
Let's use a custom install handler and handle failures gracefully.
This does not *solve* the root cause of issue #30573, but should improve
the situation when the issue is triggered.
(cherry picked from commit db6b214f95aa42f9a9fa3d94a3c6492cc57b58fb)
Related: RHEL-31756
---
src/core/unit.c | 30 ++++++++++++++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/src/core/unit.c b/src/core/unit.c
index 5a091b3bc4..9e349402ff 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -3486,6 +3486,32 @@ int unit_load_related_unit(Unit *u, const char *type, Unit **_found) {
return r;
}
+static int signal_name_owner_changed_install_handler(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Unit *u = ASSERT_PTR(userdata);
+ const sd_bus_error *e;
+ int r;
+
+ e = sd_bus_message_get_error(message);
+ if (!e) {
+ log_unit_trace(u, "Successfully installed NameOwnerChanged signal match.");
+ return 0;
+ }
+
+ r = sd_bus_error_get_errno(e);
+ log_unit_error_errno(u, r,
+ "Unexpected error response on installing NameOwnerChanged signal match: %s",
+ bus_error_message(e, r));
+
+ /* If we failed to install NameOwnerChanged signal, also unref the bus slot of GetNameOwner(). */
+ u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
+ u->get_name_owner_slot = sd_bus_slot_unref(u->get_name_owner_slot);
+
+ if (UNIT_VTABLE(u)->bus_name_owner_change)
+ UNIT_VTABLE(u)->bus_name_owner_change(u, NULL);
+
+ return 0;
+}
+
static int signal_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *new_owner;
Unit *u = ASSERT_PTR(userdata);
@@ -3568,10 +3594,10 @@ int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
r = bus_add_match_full(
bus,
&u->match_bus_slot,
- true,
+ /* asynchronous = */ true,
match,
signal_name_owner_changed,
- NULL,
+ signal_name_owner_changed_install_handler,
u,
timeout_usec);
if (r < 0)

View File

@ -0,0 +1,180 @@
From 5917dd6d4667ed4f97b63baaa3b35e2c1410f3c0 Mon Sep 17 00:00:00 2001
From: Ronan Pigott <ronan@rjp.ie>
Date: Thu, 28 Nov 2024 12:53:32 -0700
Subject: [PATCH] dbus: stash the subscriber list when we disconenct from the
bus
If we unexpectly disconnect from the bus, systemd would end up dropping
the list of subscribers, which breaks the ability of clients like logind
to monitor the state of units.
Stash the list of subscribers into the deserialized state in the event
of a disconnect so that when we recover we can renew the broken
subscriptions.
(cherry picked from commit 8402ca04d1a063c3d8a9e3d5c16df8bb8778ae98)
Related: RHEL-31756
---
src/core/dbus.c | 21 +++++++++++++++------
src/core/dbus.h | 2 +-
src/core/manager.c | 8 ++++----
src/shared/bus-util.c | 22 ++++++++++++++++++++++
src/shared/bus-util.h | 1 +
5 files changed, 43 insertions(+), 11 deletions(-)
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 1431e079c2..12a6f2fa27 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -834,6 +834,8 @@ int bus_init_api(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to set up API bus: %m");
+ (void) bus_track_coldplug(bus, &m->subscribed, /* recursive= */ false, m->deserialized_subscribed);
+ m->deserialized_subscribed = strv_free(m->deserialized_subscribed);
m->api_bus = TAKE_PTR(bus);
return 0;
@@ -986,8 +988,17 @@ static void destroy_bus(Manager *m, sd_bus **bus) {
}
/* Get rid of tracked clients on this bus */
- if (m->subscribed && sd_bus_track_get_bus(m->subscribed) == *bus)
+ if (m->subscribed && sd_bus_track_get_bus(m->subscribed) == *bus) {
+ _cleanup_strv_free_ char **subscribed = NULL;
+ int r;
+
+ r = bus_track_to_strv(m->subscribed, &subscribed);
+ if (r < 0)
+ log_warning_errno(r, "Failed to serialize api subscribers, ignoring: %m");
+ strv_free_and_replace(m->deserialized_subscribed, subscribed);
+
m->subscribed = sd_bus_track_unref(m->subscribed);
+ }
HASHMAP_FOREACH(j, m->jobs)
if (j->bus_track && sd_bus_track_get_bus(j->bus_track) == *bus)
@@ -1046,7 +1057,6 @@ void bus_done(Manager *m) {
assert(!m->subscribed);
- m->deserialized_subscribed = strv_free(m->deserialized_subscribed);
bus_verify_polkit_async_registry_free(m->polkit_registry);
}
@@ -1137,20 +1147,19 @@ void bus_track_serialize(sd_bus_track *t, FILE *f, const char *prefix) {
}
}
-int bus_track_coldplug(Manager *m, sd_bus_track **t, bool recursive, char **l) {
+int bus_track_coldplug(sd_bus *bus, sd_bus_track **t, bool recursive, char **l) {
int r;
- assert(m);
assert(t);
if (strv_isempty(l))
return 0;
- if (!m->api_bus)
+ if (!bus)
return 0;
if (!*t) {
- r = sd_bus_track_new(m->api_bus, t, NULL, NULL);
+ r = sd_bus_track_new(bus, t, NULL, NULL);
if (r < 0)
return r;
}
diff --git a/src/core/dbus.h b/src/core/dbus.h
index 50e7bb400e..3f0d902c89 100644
--- a/src/core/dbus.h
+++ b/src/core/dbus.h
@@ -19,7 +19,7 @@ void bus_done(Manager *m);
int bus_fdset_add_all(Manager *m, FDSet *fds);
void bus_track_serialize(sd_bus_track *t, FILE *f, const char *prefix);
-int bus_track_coldplug(Manager *m, sd_bus_track **t, bool recursive, char **l);
+int bus_track_coldplug(sd_bus *bus, sd_bus_track **t, bool recursive, char **l);
int bus_foreach_bus(Manager *m, sd_bus_track *subscribed2, int (*send_message)(sd_bus *bus, void *userdata), void *userdata);
diff --git a/src/core/manager.c b/src/core/manager.c
index daeaa641d7..6c67780c99 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1560,6 +1560,9 @@ Manager* manager_free(Manager *m) {
free(m->switch_root);
free(m->switch_root_init);
+ sd_bus_track_unref(m->subscribed);
+ strv_free(m->deserialized_subscribed);
+
free(m->default_smack_process_label);
rlimit_free_all(m->rlimit);
@@ -1862,7 +1865,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds, const char *roo
manager_setup_bus(m);
/* Now that we are connected to all possible buses, let's deserialize who is tracking us. */
- r = bus_track_coldplug(m, &m->subscribed, false, m->deserialized_subscribed);
+ r = bus_track_coldplug(m->api_bus, &m->subscribed, false, m->deserialized_subscribed);
if (r < 0)
log_warning_errno(r, "Failed to deserialized tracked clients, ignoring: %m");
m->deserialized_subscribed = strv_free(m->deserialized_subscribed);
@@ -3412,9 +3415,6 @@ int manager_reload(Manager *m) {
/* Clean up runtime objects no longer referenced */
manager_vacuum(m);
- /* Clean up deserialized tracked clients */
- m->deserialized_subscribed = strv_free(m->deserialized_subscribed);
-
/* Consider the reload process complete now. */
assert(m->n_reloading > 0);
m->n_reloading--;
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index d09ec5148d..9293f10fdc 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -495,6 +495,28 @@ int bus_track_add_name_many(sd_bus_track *t, char **l) {
return r;
}
+int bus_track_to_strv(sd_bus_track *t, char ***ret) {
+ _cleanup_strv_free_ char **subscribed = NULL;
+ int r = 0;
+
+ assert(ret);
+
+ for (const char *n = sd_bus_track_first(t); n; n = sd_bus_track_next(t)) {
+ r = sd_bus_track_count_name(t, n);
+ if (r < 0)
+ return r;
+
+ for (int j = 0; j < r; j++) {
+ r = strv_extend(&subscribed, n);
+ if (r < 0)
+ return r;
+ }
+ }
+
+ *ret = TAKE_PTR(subscribed);
+ return r;
+}
+
int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *description) {
_cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
const char *e;
diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h
index 955cdcb57c..e1fdf2ef48 100644
--- a/src/shared/bus-util.h
+++ b/src/shared/bus-util.h
@@ -52,6 +52,7 @@ int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id,
int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external);
int bus_track_add_name_many(sd_bus_track *t, char **l);
+int bus_track_to_strv(sd_bus_track *t, char ***ret);
int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *description);
static inline int bus_open_system_watch_bind(sd_bus **ret) {

View File

@ -0,0 +1,94 @@
From 435d53448b8c427dc1b61b4d27342fb593185acf Mon Sep 17 00:00:00 2001
From: Ronan Pigott <ronan@rjp.ie>
Date: Wed, 11 Dec 2024 12:47:10 -0700
Subject: [PATCH] manager: s/deserialized_subscribed/subscribed_as_strv
Now that this field may get populated at runtime, the deserialized name
is misleading. Change the name to reflect its updated purpose.
(cherry picked from commit e1315a621ae26473fcc9cd0d6013836f5f498d40)
Related: RHEL-31756
---
src/core/dbus.c | 6 +++---
src/core/manager-serialize.c | 2 +-
src/core/manager.c | 6 +++---
src/core/manager.h | 2 +-
4 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 12a6f2fa27..7655427f38 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -834,8 +834,8 @@ int bus_init_api(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to set up API bus: %m");
- (void) bus_track_coldplug(bus, &m->subscribed, /* recursive= */ false, m->deserialized_subscribed);
- m->deserialized_subscribed = strv_free(m->deserialized_subscribed);
+ (void) bus_track_coldplug(bus, &m->subscribed, /* recursive= */ false, m->subscribed_as_strv);
+ m->subscribed_as_strv = strv_free(m->subscribed_as_strv);
m->api_bus = TAKE_PTR(bus);
return 0;
@@ -995,7 +995,7 @@ static void destroy_bus(Manager *m, sd_bus **bus) {
r = bus_track_to_strv(m->subscribed, &subscribed);
if (r < 0)
log_warning_errno(r, "Failed to serialize api subscribers, ignoring: %m");
- strv_free_and_replace(m->deserialized_subscribed, subscribed);
+ strv_free_and_replace(m->subscribed_as_strv, subscribed);
m->subscribed = sd_bus_track_unref(m->subscribed);
}
diff --git a/src/core/manager-serialize.c b/src/core/manager-serialize.c
index f3b2d7ee16..a87d490219 100644
--- a/src/core/manager-serialize.c
+++ b/src/core/manager-serialize.c
@@ -529,7 +529,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
(void) exec_runtime_deserialize_one(m, val, fds);
else if ((val = startswith(l, "subscribed="))) {
- if (strv_extend(&m->deserialized_subscribed, val) < 0)
+ if (strv_extend(&m->subscribed_as_strv, val) < 0)
return -ENOMEM;
} else if ((val = startswith(l, "varlink-server-socket-address="))) {
if (!m->varlink_server && MANAGER_IS_SYSTEM(m)) {
diff --git a/src/core/manager.c b/src/core/manager.c
index 6c67780c99..45676d3def 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1561,7 +1561,7 @@ Manager* manager_free(Manager *m) {
free(m->switch_root_init);
sd_bus_track_unref(m->subscribed);
- strv_free(m->deserialized_subscribed);
+ strv_free(m->subscribed_as_strv);
free(m->default_smack_process_label);
@@ -1865,10 +1865,10 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds, const char *roo
manager_setup_bus(m);
/* Now that we are connected to all possible buses, let's deserialize who is tracking us. */
- r = bus_track_coldplug(m->api_bus, &m->subscribed, false, m->deserialized_subscribed);
+ r = bus_track_coldplug(m->api_bus, &m->subscribed, false, m->subscribed_as_strv);
if (r < 0)
log_warning_errno(r, "Failed to deserialized tracked clients, ignoring: %m");
- m->deserialized_subscribed = strv_free(m->deserialized_subscribed);
+ m->subscribed_as_strv = strv_free(m->subscribed_as_strv);
r = manager_varlink_init(m);
if (r < 0)
diff --git a/src/core/manager.h b/src/core/manager.h
index 86e7e40989..a96ba7bf9d 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -276,7 +276,7 @@ struct Manager {
considered subscribes, since they last for very short only,
and it is much simpler that way. */
sd_bus_track *subscribed;
- char **deserialized_subscribed;
+ char **subscribed_as_strv;
/* This is used during reloading: before the reload we queue
* the reply message here, and afterwards we send it */

View File

@ -0,0 +1,55 @@
From da904dede254800cdbac51905db9423f8f88fefa Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Sat, 11 Jan 2025 16:26:55 +0100
Subject: [PATCH] bus-util: do not reset the count returned by
sd_bus_track_count_name()
Follow-up for 8402ca04d1a063c3d8a9e3d5c16df8bb8778ae98
While at it, turn the retval check for sd_bus_track_count_name()
into assertion, given we're working with already established tracks
(service_name_is_valid() should never yield false in this case).
Addresses https://github.com/systemd/systemd/pull/35406#discussion_r1912066774
(cherry picked from commit 33eeea4128f31df7ab4bd8866b582062d70114ae)
Related: RHEL-31756
---
src/shared/bus-util.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 9293f10fdc..5e6d17d201 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -497,16 +497,15 @@ int bus_track_add_name_many(sd_bus_track *t, char **l) {
int bus_track_to_strv(sd_bus_track *t, char ***ret) {
_cleanup_strv_free_ char **subscribed = NULL;
- int r = 0;
+ int r;
assert(ret);
for (const char *n = sd_bus_track_first(t); n; n = sd_bus_track_next(t)) {
- r = sd_bus_track_count_name(t, n);
- if (r < 0)
- return r;
+ int c = sd_bus_track_count_name(t, n);
+ assert(c >= 0);
- for (int j = 0; j < r; j++) {
+ for (int j = 0; j < c; j++) {
r = strv_extend(&subscribed, n);
if (r < 0)
return r;
@@ -514,7 +513,7 @@ int bus_track_to_strv(sd_bus_track *t, char ***ret) {
}
*ret = TAKE_PTR(subscribed);
- return r;
+ return 0;
}
int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *description) {

View File

@ -0,0 +1,31 @@
From 02e5c4076ce3981fb2b0c7830197b2f13e225efe Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Mon, 13 Jan 2025 17:30:51 +0100
Subject: [PATCH] core/manager: restore bus track deserialization cleanup in
manager_reload()
There's zero explanation why it got (spuriously) removed in
8402ca04d1a063c3d8a9e3d5c16df8bb8778ae98...
(cherry picked from commit 34f4b817f67b002eae7e2c09b19bf4b66c4791b6)
Related: RHEL-31756
---
src/core/manager.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/core/manager.c b/src/core/manager.c
index 45676d3def..92f283d33d 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -3409,6 +3409,10 @@ int manager_reload(Manager *m) {
(void) manager_setup_cgroups_agent(m);
(void) manager_setup_user_lookup_fd(m);
+ /* Clean up deserialized bus track information. They're never consumed during reload (as opposed to
+ * reexec) since we do not disconnect from the bus. */
+ m->subscribed_as_strv = strv_free(m->subscribed_as_strv);
+
/* Third, fire things up! */
manager_coldplug(m);

View File

@ -0,0 +1,32 @@
From 8e451eebfe6f37bacb02543d9a38c4ddaa6f8400 Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Sat, 11 Jan 2025 18:38:49 +0100
Subject: [PATCH] core/manager: drop duplicate bus track deserialization
bus_init_api() now does this internally
(after 8402ca04d1a063c3d8a9e3d5c16df8bb8778ae98).
(cherry picked from commit af0e10354e567bfd0b9521376b2aad55f12a4e3d)
Related: RHEL-31756
---
src/core/manager.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/src/core/manager.c b/src/core/manager.c
index 92f283d33d..653b0c2d22 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1864,12 +1864,6 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds, const char *roo
/* Connect to the bus if we are good for it */
manager_setup_bus(m);
- /* Now that we are connected to all possible buses, let's deserialize who is tracking us. */
- r = bus_track_coldplug(m->api_bus, &m->subscribed, false, m->subscribed_as_strv);
- if (r < 0)
- log_warning_errno(r, "Failed to deserialized tracked clients, ignoring: %m");
- m->subscribed_as_strv = strv_free(m->subscribed_as_strv);
-
r = manager_varlink_init(m);
if (r < 0)
log_warning_errno(r, "Failed to set up Varlink, ignoring: %m");

View File

@ -0,0 +1,102 @@
From f18c7dd568ba87c6aa9a045878c0a9ef7c23208e Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Thu, 31 Jul 2025 18:26:09 +0200
Subject: [PATCH] sd-bus/bus-track: use install_callback in
sd_bus_track_add_name()
Previously we didn't provide any install_callback to
sd_bus_add_match_async() so in case AddMatch() method call timed out we
destroyed the bus connection. This seems overly aggressive and simply
updating the sd_bus_track object accordingly should be enough.
Follow-up for 37ce3fd2b7dd8f81f6f4bca2003961a92b2963dc.
Fixes #32381
(cherry picked from commit dcf42d1ee21222ee698e5e0ab3ecf3411b63da40)
Related: RHEL-31756
---
src/libsystemd/sd-bus/bus-track.c | 32 +++++++++++++++++++++++++++----
1 file changed, 28 insertions(+), 4 deletions(-)
diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c
index f9c59a1007..276e177d2b 100644
--- a/src/libsystemd/sd-bus/bus-track.c
+++ b/src/libsystemd/sd-bus/bus-track.c
@@ -3,6 +3,7 @@
#include "sd-bus.h"
#include "alloc-util.h"
+#include "bus-error.h"
#include "bus-internal.h"
#include "bus-track.h"
#include "string-util.h"
@@ -11,6 +12,7 @@ struct track_item {
unsigned n_ref;
char *name;
sd_bus_slot *slot;
+ sd_bus_track *track;
};
struct sd_bus_track {
@@ -163,18 +165,39 @@ static sd_bus_track *track_free(sd_bus_track *track) {
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_bus_track, sd_bus_track, track_free);
-static int on_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- sd_bus_track *track = ASSERT_PTR(userdata);
+static int on_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *reterr_error) {
+ struct track_item *item = ASSERT_PTR(userdata);
const char *name;
int r;
assert(message);
+ assert(item->track);
r = sd_bus_message_read(message, "sss", &name, NULL, NULL);
if (r < 0)
return 0;
- bus_track_remove_name_fully(track, name);
+ bus_track_remove_name_fully(item->track, name);
+ return 0;
+}
+
+static int name_owner_changed_install_callback(sd_bus_message *message, void *userdata, sd_bus_error *reterr_error) {
+ struct track_item *item = ASSERT_PTR(userdata);
+ const sd_bus_error *e;
+ int r;
+
+ assert(message);
+ assert(item->track);
+ assert(item->name);
+
+ e = sd_bus_message_get_error(message);
+ if (!e)
+ return 0;
+
+ r = sd_bus_error_get_errno(e);
+ log_debug_errno(r, "Failed to install match for tracking name '%s': %s", item->name, bus_error_message(e, r));
+
+ bus_track_remove_name_fully(item->track, item->name);
return 0;
}
@@ -216,6 +239,7 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
*n = (struct track_item) {
.n_ref = 1,
+ .track = track,
};
n->name = strdup(name);
@@ -227,7 +251,7 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
bus_track_remove_from_queue(track); /* don't dispatch this while we work in it */
- r = sd_bus_add_match_async(track->bus, &n->slot, match, on_name_owner_changed, NULL, track);
+ r = sd_bus_add_match_async(track->bus, &n->slot, match, on_name_owner_changed, name_owner_changed_install_callback, n);
if (r < 0) {
bus_track_add_to_queue(track);
return r;

View File

@ -0,0 +1,38 @@
From 9f940102616443911fff789aae63546c1da3138e Mon Sep 17 00:00:00 2001
From: Luca Boccassi <luca.boccassi@gmail.com>
Date: Tue, 18 Feb 2025 21:15:08 +0000
Subject: [PATCH] shell completion: add kernel-identify/inspect verbs for
bootctl
Follow-up for a05255981ba5b04f1cf54ea656fbce1dfd9c3a68
Follow-up for 3e0a3a0259324b4c40a9a62c8506fe683cd0273b
(cherry picked from commit 6a6d4c3f3c123a1cbb6770f1cae8c130a48333e1)
Resolves: RHEL-108576
---
shell-completion/bash/bootctl | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/shell-completion/bash/bootctl b/shell-completion/bash/bootctl
index 0b7cef7871..328289e0cf 100644
--- a/shell-completion/bash/bootctl
+++ b/shell-completion/bash/bootctl
@@ -70,6 +70,7 @@ _bootctl() {
[STANDALONE]='help status install update remove is-installed random-seed systemd-efi-options list set-timeout set-timeout-oneshot'
[BOOTENTRY]='set-default set-oneshot'
[BOOLEAN]='reboot-to-firmware'
+ [FILE]='kernel-identify kernel-inspect'
)
for ((i=0; i < COMP_CWORD; i++)); do
@@ -100,6 +101,9 @@ _bootctl() {
fi
elif __contains_word "$verb" ${VERBS[BOOLEAN]}; then
comps="yes no"
+ elif __contains_word "$verb" ${VERBS[FILE]}; then
+ comps=$( compgen -A file -- "$cur" )
+ compopt -o filenames
fi
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )

View File

@ -0,0 +1,444 @@
From 05b4623cb23c6f083a5bee9769e5cd22d8ff4e16 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Sun, 12 Feb 2023 05:30:49 +0900
Subject: [PATCH] test: add tests for format_timestamp() and parse_timestamp()
with various timezone
(cherry picked from commit 8b51c41fd0796b1299f3b7f2f11eaf4efae8c2db)
Related: RHEL-109488
---
src/test/test-time-util.c | 378 ++++++++++++++++++++++++++++++++++++--
1 file changed, 366 insertions(+), 12 deletions(-)
diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c
index 6b546fb9f5..3fbf7bf3d0 100644
--- a/src/test/test-time-util.c
+++ b/src/test/test-time-util.c
@@ -1,6 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include "dirent-util.h"
#include "env-util.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "random-util.h"
#include "serialize.h"
#include "string-util.h"
@@ -8,6 +11,8 @@
#include "tests.h"
#include "time-util.h"
+#define TRIAL 100u
+
TEST(parse_sec) {
usec_t u;
@@ -334,11 +339,11 @@ TEST(usec_sub_signed) {
}
TEST(format_timestamp) {
- for (unsigned i = 0; i < 100; i++) {
+ for (unsigned i = 0; i < TRIAL; i++) {
char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)];
usec_t x, y;
- x = random_u64_range(2147483600 * USEC_PER_SEC) + 1;
+ x = random_u64_range(USEC_TIMESTAMP_FORMATTABLE_MAX - USEC_PER_SEC) + USEC_PER_SEC;
assert_se(format_timestamp(buf, sizeof(buf), x));
log_debug("%s", buf);
@@ -377,20 +382,91 @@ TEST(format_timestamp) {
}
}
+static void test_format_timestamp_impl(usec_t x) {
+ bool success;
+ const char *xx, *yy;
+ usec_t y;
+
+ xx = FORMAT_TIMESTAMP(x);
+ assert_se(xx);
+ assert_se(parse_timestamp(xx, &y) >= 0);
+ yy = FORMAT_TIMESTAMP(y);
+ assert_se(yy);
+
+ success = (x / USEC_PER_SEC == y / USEC_PER_SEC) && streq(xx, yy);
+ log_full(success ? LOG_DEBUG : LOG_ERR, "@" USEC_FMT " → %s → @" USEC_FMT " → %s", x, xx, y, yy);
+ assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
+ assert_se(streq(xx, yy));
+}
+
+static void test_format_timestamp_loop(void) {
+ test_format_timestamp_impl(USEC_PER_SEC);
+
+ for (unsigned i = 0; i < TRIAL; i++) {
+ usec_t x;
+
+ x = random_u64_range(USEC_TIMESTAMP_FORMATTABLE_MAX - USEC_PER_SEC) + USEC_PER_SEC;
+ test_format_timestamp_impl(x);
+ }
+}
+
TEST(FORMAT_TIMESTAMP) {
- for (unsigned i = 0; i < 100; i++) {
- _cleanup_free_ char *buf;
- usec_t x, y;
+ test_format_timestamp_loop();
+}
- x = random_u64_range(2147483600 * USEC_PER_SEC) + 1;
+static void test_format_timestamp_with_tz_one(const char *name1, const char *name2) {
+ _cleanup_free_ char *buf = NULL, *tz = NULL;
+ const char *name, *saved_tz;
- /* strbuf() is to test the macro in an argument to a function call. */
- assert_se(buf = strdup(FORMAT_TIMESTAMP(x)));
- log_debug("%s", buf);
- assert_se(parse_timestamp(buf, &y) >= 0);
- assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
+ if (name2)
+ assert_se(buf = path_join(name1, name2));
+ name = buf ?: name1;
+
+ if (!timezone_is_valid(name, LOG_DEBUG))
+ return;
- assert_se(streq(FORMAT_TIMESTAMP(x), buf));
+ log_info("/* %s(%s) */", __func__, name);
+
+ saved_tz = getenv("TZ");
+
+ assert_se(tz = strjoin(":", name));
+ assert_se(setenv("TZ", tz, 1) >= 0);
+ tzset();
+ log_debug("%s: tzname[0]=%s, tzname[1]=%s", tz, strempty(tzname[0]), strempty(tzname[1]));
+
+ test_format_timestamp_loop();
+
+ assert_se(set_unset_env("TZ", saved_tz, true) == 0);
+ tzset();
+}
+
+TEST(FORMAT_TIMESTAMP_with_tz) {
+ if (!slow_tests_enabled())
+ return (void) log_tests_skipped("slow tests are disabled");
+
+ _cleanup_closedir_ DIR *dir = opendir("/usr/share/zoneinfo");
+ if (!dir)
+ return (void) log_tests_skipped_errno(errno, "Failed to open /usr/share/zoneinfo");
+
+ FOREACH_DIRENT(de, dir, break) {
+ if (de->d_type == DT_REG)
+ test_format_timestamp_with_tz_one(de->d_name, NULL);
+
+ else if (de->d_type == DT_DIR) {
+ if (streq(de->d_name, "right"))
+ /* The test does not support timezone with leap second info. */
+ continue;
+
+ _cleanup_closedir_ DIR *subdir = xopendirat(dirfd(dir), de->d_name, 0);
+ if (!subdir) {
+ log_notice_errno(errno, "Failed to open /usr/share/zoneinfo/%s, ignoring: %m", de->d_name);
+ continue;
+ }
+
+ FOREACH_DIRENT(subde, subdir, break)
+ if (subde->d_type == DT_REG)
+ test_format_timestamp_with_tz_one(de->d_name, subde->d_name);
+ }
}
}
@@ -490,6 +566,219 @@ TEST(format_timestamp_utc) {
test_format_timestamp_utc_one(USEC_INFINITY, NULL);
}
+static void test_parse_timestamp_one(const char *str, usec_t max_diff, usec_t expected) {
+ usec_t usec;
+
+ log_debug("/* %s(%s) */", __func__, str);
+ assert_se(parse_timestamp(str, &usec) >= 0);
+ assert_se(usec >= expected);
+ assert_se(usec_sub_unsigned(usec, expected) <= max_diff);
+}
+
+TEST(parse_timestamp) {
+ usec_t today, now_usec;
+
+ /* UTC */
+ test_parse_timestamp_one("Thu 1970-01-01 00:01 UTC", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("Thu 1970-01-01 00:00:01 UTC", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("Thu 1970-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("Thu 1970-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("Thu 70-01-01 00:01 UTC", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("Thu 70-01-01 00:00:01 UTC", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("Thu 70-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("Thu 70-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("1970-01-01 00:01 UTC", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("1970-01-01 00:00:01 UTC", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("1970-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("1970-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("70-01-01 00:01 UTC", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("70-01-01 00:00:01 UTC", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("70-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("70-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000);
+
+ if (timezone_is_valid("Asia/Tokyo", LOG_DEBUG)) {
+ /* Asia/Tokyo (+0900) */
+ test_parse_timestamp_one("Thu 1970-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("Thu 1970-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("Thu 1970-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("Thu 1970-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("Thu 70-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("Thu 70-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("Thu 70-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("Thu 70-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("1970-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("1970-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("1970-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("1970-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("70-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("70-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("70-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("70-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
+
+ const char *saved_tz = getenv("TZ");
+ assert_se(setenv("TZ", ":Asia/Tokyo", 1) >= 0);
+
+ /* JST (+0900) */
+ test_parse_timestamp_one("Thu 1970-01-01 09:01 JST", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("Thu 1970-01-01 09:00:01 JST", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("Thu 1970-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("Thu 1970-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("Thu 70-01-01 09:01 JST", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("Thu 70-01-01 09:00:01 JST", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("Thu 70-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("Thu 70-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("1970-01-01 09:01 JST", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("1970-01-01 09:00:01 JST", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("1970-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("1970-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("70-01-01 09:01 JST", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("70-01-01 09:00:01 JST", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("70-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("70-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000);
+
+ assert_se(set_unset_env("TZ", saved_tz, true) == 0);
+ }
+
+ if (timezone_is_valid("America/New_York", LOG_DEBUG)) {
+ /* America/New_York (-0500) */
+ test_parse_timestamp_one("Wed 1969-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("Wed 1969-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("Wed 1969-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("Wed 1969-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("Wed 69-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("Wed 69-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("Wed 69-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("Wed 69-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("1969-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("1969-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("1969-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("1969-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("69-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("69-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("69-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("69-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000);
+
+ const char *saved_tz = getenv("TZ");
+ assert_se(setenv("TZ", ":America/New_York", 1) >= 0);
+
+ /* EST (-0500) */
+ test_parse_timestamp_one("Wed 1969-12-31 19:01 EST", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("Wed 1969-12-31 19:00:01 EST", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("Wed 1969-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("Wed 1969-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("Wed 69-12-31 19:01 EST", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("Wed 69-12-31 19:00:01 EST", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("Wed 69-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("Wed 69-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("1969-12-31 19:01 EST", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("1969-12-31 19:00:01 EST", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("1969-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("1969-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("69-12-31 19:01 EST", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("69-12-31 19:00:01 EST", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("69-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("69-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000);
+
+ assert_se(set_unset_env("TZ", saved_tz, true) == 0);
+ }
+
+ /* -06 */
+ test_parse_timestamp_one("Wed 1969-12-31 18:01 -06", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("Wed 1969-12-31 18:00:01 -06", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("Wed 1969-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("Wed 1969-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("Wed 69-12-31 18:01 -06", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("Wed 69-12-31 18:00:01 -06", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("Wed 69-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("Wed 69-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("1969-12-31 18:01 -06", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("1969-12-31 18:00:01 -06", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("1969-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("1969-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("69-12-31 18:01 -06", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("69-12-31 18:00:01 -06", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("69-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("69-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000);
+
+ /* -0600 */
+ test_parse_timestamp_one("Wed 1969-12-31 18:01 -0600", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("Wed 1969-12-31 18:00:01 -0600", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("Wed 1969-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("Wed 1969-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("Wed 69-12-31 18:01 -0600", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("Wed 69-12-31 18:00:01 -0600", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("Wed 69-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("Wed 69-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("1969-12-31 18:01 -0600", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("1969-12-31 18:00:01 -0600", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("1969-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("1969-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("69-12-31 18:01 -0600", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("69-12-31 18:00:01 -0600", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("69-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("69-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000);
+
+ /* -06:00 */
+ test_parse_timestamp_one("Wed 1969-12-31 18:01 -06:00", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("Wed 1969-12-31 18:00:01 -06:00", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("Wed 1969-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("Wed 1969-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("Wed 69-12-31 18:01 -06:00", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("Wed 69-12-31 18:00:01 -06:00", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("Wed 69-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("Wed 69-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("1969-12-31 18:01 -06:00", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("1969-12-31 18:00:01 -06:00", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("1969-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("1969-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000);
+
+ test_parse_timestamp_one("69-12-31 18:01 -06:00", 0, USEC_PER_MINUTE);
+ test_parse_timestamp_one("69-12-31 18:00:01 -06:00", 0, USEC_PER_SEC);
+ test_parse_timestamp_one("69-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("69-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000);
+
+ /* without date */
+ assert_se(parse_timestamp("today", &today) == 0);
+ test_parse_timestamp_one("00:01", 0, today + USEC_PER_MINUTE);
+ test_parse_timestamp_one("00:00:01", 0, today + USEC_PER_SEC);
+ test_parse_timestamp_one("00:00:01.001", 0, today + USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("00:00:01.0010", 0, today + USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("tomorrow", 0, today + USEC_PER_DAY);
+ test_parse_timestamp_one("yesterday", 0, today - USEC_PER_DAY);
+
+ /* relative */
+ assert_se(parse_timestamp("now", &now_usec) == 0);
+ test_parse_timestamp_one("+5hours", USEC_PER_MINUTE, now_usec + 5 * USEC_PER_HOUR);
+ if (now_usec >= 10 * USEC_PER_DAY)
+ test_parse_timestamp_one("-10days", USEC_PER_MINUTE, now_usec - 10 * USEC_PER_DAY);
+ test_parse_timestamp_one("2weeks left", USEC_PER_MINUTE, now_usec + 2 * USEC_PER_WEEK);
+ if (now_usec >= 30 * USEC_PER_MINUTE)
+ test_parse_timestamp_one("30minutes ago", USEC_PER_MINUTE, now_usec - 30 * USEC_PER_MINUTE);
+}
+
TEST(deserialize_dual_timestamp) {
int r;
dual_timestamp t;
@@ -613,6 +902,71 @@ TEST(map_clock_usec) {
}
}
+static void test_timezone_offset_change_one(const char *utc, const char *pretty) {
+ usec_t x, y, z;
+ char *s;
+
+ assert_se(parse_timestamp(utc, &x) >= 0);
+
+ s = FORMAT_TIMESTAMP_STYLE(x, TIMESTAMP_UTC);
+ assert_se(parse_timestamp(s, &y) >= 0);
+ log_debug("%s -> " USEC_FMT " -> %s -> " USEC_FMT, utc, x, s, y);
+ assert_se(streq(s, utc));
+ assert_se(x == y);
+
+ assert_se(parse_timestamp(pretty, &y) >= 0);
+ s = FORMAT_TIMESTAMP_STYLE(y, TIMESTAMP_PRETTY);
+ assert_se(parse_timestamp(s, &z) >= 0);
+ log_debug("%s -> " USEC_FMT " -> %s -> " USEC_FMT, pretty, y, s, z);
+ assert_se(streq(s, pretty));
+ assert_se(x == y);
+ assert_se(x == z);
+}
+
+TEST(timezone_offset_change) {
+ const char *tz = getenv("TZ");
+
+ /* See issue #26370. */
+
+ if (timezone_is_valid("Africa/Casablanca", LOG_DEBUG)) {
+ assert_se(setenv("TZ", ":Africa/Casablanca", 1) >= 0);
+ tzset();
+ log_debug("Africa/Casablanca: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1]));
+
+ test_timezone_offset_change_one("Sun 2015-10-25 01:59:59 UTC", "Sun 2015-10-25 02:59:59 +01");
+ test_timezone_offset_change_one("Sun 2015-10-25 02:00:00 UTC", "Sun 2015-10-25 02:00:00 +00");
+ test_timezone_offset_change_one("Sun 2018-06-17 01:59:59 UTC", "Sun 2018-06-17 01:59:59 +00");
+ test_timezone_offset_change_one("Sun 2018-06-17 02:00:00 UTC", "Sun 2018-06-17 03:00:00 +01");
+ test_timezone_offset_change_one("Sun 2018-10-28 01:59:59 UTC", "Sun 2018-10-28 02:59:59 +01");
+ test_timezone_offset_change_one("Sun 2018-10-28 02:00:00 UTC", "Sun 2018-10-28 03:00:00 +01");
+ }
+
+ if (timezone_is_valid("Asia/Atyrau", LOG_DEBUG)) {
+ assert_se(setenv("TZ", ":Asia/Atyrau", 1) >= 0);
+ tzset();
+ log_debug("Asia/Atyrau: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1]));
+
+ test_timezone_offset_change_one("Sat 2004-03-27 21:59:59 UTC", "Sun 2004-03-28 01:59:59 +04");
+ test_timezone_offset_change_one("Sat 2004-03-27 22:00:00 UTC", "Sun 2004-03-28 03:00:00 +05");
+ test_timezone_offset_change_one("Sat 2004-10-30 21:59:59 UTC", "Sun 2004-10-31 02:59:59 +05");
+ test_timezone_offset_change_one("Sat 2004-10-30 22:00:00 UTC", "Sun 2004-10-31 03:00:00 +05");
+ }
+
+ if (timezone_is_valid("Chile/EasterIsland", LOG_DEBUG)) {
+ assert_se(setenv("TZ", ":Chile/EasterIsland", 1) >= 0);
+ tzset();
+ log_debug("Chile/EasterIsland: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1]));
+
+ test_timezone_offset_change_one("Sun 1981-10-11 03:59:59 UTC", "Sat 1981-10-10 20:59:59 -07");
+ test_timezone_offset_change_one("Sun 1981-10-11 04:00:00 UTC", "Sat 1981-10-10 22:00:00 -06");
+ test_timezone_offset_change_one("Sun 1982-03-14 02:59:59 UTC", "Sat 1982-03-13 20:59:59 -06");
+ test_timezone_offset_change_one("Sun 1982-03-14 03:00:00 UTC", "Sat 1982-03-13 21:00:00 -06");
+ }
+
+ assert_se(set_unset_env("TZ", tz, true) == 0);
+ tzset();
+}
+
static int intro(void) {
log_info("realtime=" USEC_FMT "\n"
"monotonic=" USEC_FMT "\n"

View File

@ -0,0 +1,52 @@
From c7a62e108ffbe41ccf1bb5fba4b5a37daf317939 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Fri, 15 Aug 2025 15:12:14 +0200
Subject: [PATCH] test-time-util: disable failing tests
Presumably they depend on fixes that we don't have yet. And I don't want
to backport stuff not relevant to the "--when" feature as a part of this
PR.
RHEL-only: ci
Related: RHEL-109488
---
src/test/test-time-util.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c
index 3fbf7bf3d0..f2acb6159a 100644
--- a/src/test/test-time-util.c
+++ b/src/test/test-time-util.c
@@ -697,6 +697,7 @@ TEST(parse_timestamp) {
assert_se(set_unset_env("TZ", saved_tz, true) == 0);
}
+#if 0
/* -06 */
test_parse_timestamp_one("Wed 1969-12-31 18:01 -06", 0, USEC_PER_MINUTE);
test_parse_timestamp_one("Wed 1969-12-31 18:00:01 -06", 0, USEC_PER_SEC);
@@ -759,6 +760,7 @@ TEST(parse_timestamp) {
test_parse_timestamp_one("69-12-31 18:00:01 -06:00", 0, USEC_PER_SEC);
test_parse_timestamp_one("69-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000);
test_parse_timestamp_one("69-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000);
+#endif
/* without date */
assert_se(parse_timestamp("today", &today) == 0);
@@ -941,6 +943,7 @@ TEST(timezone_offset_change) {
test_timezone_offset_change_one("Sun 2018-10-28 02:00:00 UTC", "Sun 2018-10-28 03:00:00 +01");
}
+#if 0
if (timezone_is_valid("Asia/Atyrau", LOG_DEBUG)) {
assert_se(setenv("TZ", ":Asia/Atyrau", 1) >= 0);
tzset();
@@ -962,6 +965,7 @@ TEST(timezone_offset_change) {
test_timezone_offset_change_one("Sun 1982-03-14 02:59:59 UTC", "Sat 1982-03-13 20:59:59 -06");
test_timezone_offset_change_one("Sun 1982-03-14 03:00:00 UTC", "Sat 1982-03-13 21:00:00 -06");
}
+#endif
assert_se(set_unset_env("TZ", tz, true) == 0);
tzset();

View File

@ -0,0 +1,122 @@
From 9010f2b16067fbe974cd1922b596bcd526de07bc Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 3 Mar 2023 12:09:59 +0900
Subject: [PATCH] test: test parse_timestamp() in various timezone
(cherry picked from commit d8f3ad627c9a857d46d442f8ab722c1efab30d5c)
Related: RHEL-109488
---
src/test/test-time-util.c | 57 +++++++++++++++++++++++++++++----------
1 file changed, 43 insertions(+), 14 deletions(-)
diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c
index f2acb6159a..ee861135c2 100644
--- a/src/test/test-time-util.c
+++ b/src/test/test-time-util.c
@@ -567,15 +567,17 @@ TEST(format_timestamp_utc) {
}
static void test_parse_timestamp_one(const char *str, usec_t max_diff, usec_t expected) {
- usec_t usec;
+ usec_t usec = USEC_INFINITY;
+ int r;
- log_debug("/* %s(%s) */", __func__, str);
- assert_se(parse_timestamp(str, &usec) >= 0);
+ r = parse_timestamp(str, &usec);
+ log_debug("/* %s(%s): max_diff="USEC_FMT", expected="USEC_FMT", result="USEC_FMT"*/", __func__, str, max_diff, expected, usec);
+ assert_se(r >= 0);
assert_se(usec >= expected);
assert_se(usec_sub_unsigned(usec, expected) <= max_diff);
}
-TEST(parse_timestamp) {
+static void test_parse_timestamp_impl(const char *tz) {
usec_t today, now_usec;
/* UTC */
@@ -620,10 +622,9 @@ TEST(parse_timestamp) {
test_parse_timestamp_one("70-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC);
test_parse_timestamp_one("70-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
test_parse_timestamp_one("70-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
+ }
- const char *saved_tz = getenv("TZ");
- assert_se(setenv("TZ", ":Asia/Tokyo", 1) >= 0);
-
+ if (streq_ptr(tz, "Asia/Tokyo")) {
/* JST (+0900) */
test_parse_timestamp_one("Thu 1970-01-01 09:01 JST", 0, USEC_PER_MINUTE);
test_parse_timestamp_one("Thu 1970-01-01 09:00:01 JST", 0, USEC_PER_SEC);
@@ -644,8 +645,6 @@ TEST(parse_timestamp) {
test_parse_timestamp_one("70-01-01 09:00:01 JST", 0, USEC_PER_SEC);
test_parse_timestamp_one("70-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000);
test_parse_timestamp_one("70-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000);
-
- assert_se(set_unset_env("TZ", saved_tz, true) == 0);
}
if (timezone_is_valid("America/New_York", LOG_DEBUG)) {
@@ -669,10 +668,9 @@ TEST(parse_timestamp) {
test_parse_timestamp_one("69-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC);
test_parse_timestamp_one("69-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000);
test_parse_timestamp_one("69-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000);
+ }
- const char *saved_tz = getenv("TZ");
- assert_se(setenv("TZ", ":America/New_York", 1) >= 0);
-
+ if (streq_ptr(tz, "America/New_York")) {
/* EST (-0500) */
test_parse_timestamp_one("Wed 1969-12-31 19:01 EST", 0, USEC_PER_MINUTE);
test_parse_timestamp_one("Wed 1969-12-31 19:00:01 EST", 0, USEC_PER_SEC);
@@ -693,8 +691,6 @@ TEST(parse_timestamp) {
test_parse_timestamp_one("69-12-31 19:00:01 EST", 0, USEC_PER_SEC);
test_parse_timestamp_one("69-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000);
test_parse_timestamp_one("69-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000);
-
- assert_se(set_unset_env("TZ", saved_tz, true) == 0);
}
#if 0
@@ -781,6 +777,39 @@ TEST(parse_timestamp) {
test_parse_timestamp_one("30minutes ago", USEC_PER_MINUTE, now_usec - 30 * USEC_PER_MINUTE);
}
+TEST(parse_timestamp) {
+ test_parse_timestamp_impl(NULL);
+}
+
+static void test_parse_timestamp_with_tz_one(const char *tz) {
+ const char *saved_tz, *colon_tz;
+
+ if (!timezone_is_valid(tz, LOG_DEBUG))
+ return;
+
+ log_info("/* %s(%s) */", __func__, tz);
+
+ saved_tz = getenv("TZ");
+
+ assert_se(colon_tz = strjoina(":", tz));
+ assert_se(setenv("TZ", colon_tz, 1) >= 0);
+ tzset();
+ log_debug("%s: tzname[0]=%s, tzname[1]=%s", tz, strempty(tzname[0]), strempty(tzname[1]));
+
+ test_parse_timestamp_impl(tz);
+
+ assert_se(set_unset_env("TZ", saved_tz, true) == 0);
+ tzset();
+}
+
+TEST(parse_timestamp_with_tz) {
+ _cleanup_strv_free_ char **timezones = NULL;
+
+ assert_se(get_timezones(&timezones) >= 0);
+ STRV_FOREACH(tz, timezones)
+ test_parse_timestamp_with_tz_one(*tz);
+}
+
TEST(deserialize_dual_timestamp) {
int r;
dual_timestamp t;

View File

@ -0,0 +1,47 @@
From 41b7fedf9ed75f6dfa9fec03a70964b897fbf9ba Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Tue, 14 Mar 2023 06:56:17 +0800
Subject: [PATCH] systemctl: logind: add missing asserts
(cherry picked from commit 9071eea01bd26d838bfd793db497efd849ad44da)
Related: RHEL-109488
---
src/systemctl/systemctl-logind.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/systemctl/systemctl-logind.c b/src/systemctl/systemctl-logind.c
index 1c3b68f09f..f910fe6675 100644
--- a/src/systemctl/systemctl-logind.c
+++ b/src/systemctl/systemctl-logind.c
@@ -21,6 +21,8 @@ static int logind_set_wall_message(sd_bus *bus) {
_cleanup_free_ char *m = NULL;
int r;
+ assert(bus);
+
m = strv_join(arg_wall, " ");
if (!m)
return log_oom();
@@ -55,7 +57,10 @@ int logind_reboot(enum action a) {
sd_bus *bus;
int r;
- if (a < 0 || a >= _ACTION_MAX || !actions[a])
+ assert(a >= 0);
+ assert(a < _ACTION_MAX);
+
+ if (!actions[a])
return -EINVAL;
r = acquire_bus(BUS_FULL, &bus);
@@ -106,6 +111,9 @@ int logind_check_inhibitors(enum action a) {
unsigned c = 0;
int r;
+ assert(a >= 0);
+ assert(a < _ACTION_MAX);
+
if (arg_check_inhibitors == 0 || arg_force > 0)
return 0;

View File

@ -0,0 +1,70 @@
From 5085c1c72a52d6c4e8b47d91a6cd08ceec9c49cc Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Sun, 5 Mar 2023 23:11:48 +0800
Subject: [PATCH] systemctl: logind: make logind_schedule_shutdown accept
action as param
(cherry picked from commit 92b00e867844948bdf559758739343c4308570c0)
Related: RHEL-109488
---
src/systemctl/systemctl-compat-halt.c | 2 +-
src/systemctl/systemctl-logind.c | 8 +++++---
src/systemctl/systemctl-logind.h | 2 +-
3 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/systemctl/systemctl-compat-halt.c b/src/systemctl/systemctl-compat-halt.c
index 8a0e4e6294..b9164c27ab 100644
--- a/src/systemctl/systemctl-compat-halt.c
+++ b/src/systemctl/systemctl-compat-halt.c
@@ -149,7 +149,7 @@ int halt_main(void) {
if (arg_force == 0) {
/* always try logind first */
if (arg_when > 0)
- r = logind_schedule_shutdown();
+ r = logind_schedule_shutdown(arg_action);
else {
r = logind_check_inhibitors(arg_action);
if (r < 0)
diff --git a/src/systemctl/systemctl-logind.c b/src/systemctl/systemctl-logind.c
index f910fe6675..068f54e18b 100644
--- a/src/systemctl/systemctl-logind.c
+++ b/src/systemctl/systemctl-logind.c
@@ -291,19 +291,21 @@ int prepare_boot_loader_entry(void) {
#endif
}
-int logind_schedule_shutdown(void) {
-
+int logind_schedule_shutdown(enum action a) {
#if ENABLE_LOGIND
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
const char *action;
sd_bus *bus;
int r;
+ assert(a >= 0);
+ assert(a < _ACTION_MAX);
+
r = acquire_bus(BUS_FULL, &bus);
if (r < 0)
return r;
- action = action_table[arg_action].verb;
+ action = action_table[a].verb;
if (!action)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Scheduling not supported for this action.");
diff --git a/src/systemctl/systemctl-logind.h b/src/systemctl/systemctl-logind.h
index 925f4559c1..516f74952f 100644
--- a/src/systemctl/systemctl-logind.h
+++ b/src/systemctl/systemctl-logind.h
@@ -10,7 +10,7 @@ int prepare_firmware_setup(void);
int prepare_boot_loader_menu(void);
int prepare_boot_loader_entry(void);
-int logind_schedule_shutdown(void);
+int logind_schedule_shutdown(enum action a);
int logind_cancel_shutdown(void);
int logind_show_shutdown(void);

View File

@ -0,0 +1,262 @@
From 87f8db36eb01b805e7000aeb69ebfaf1c8c323b8 Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Sun, 5 Mar 2023 23:27:44 +0800
Subject: [PATCH] systemctl: add option --when for scheduled shutdown
Pass an empty string or "cancel" will cancel the action.
Pass "show" will show the scheduled actions.
Replaces #17258
(cherry picked from commit 1433e1f998465b7acf472c73d58c14e7e2eb3f13)
Resolves: RHEL-109488
---
man/systemctl.xml | 41 ++++++++++++++-----------
src/systemctl/systemctl-logind.c | 26 ++++++++++------
src/systemctl/systemctl-start-special.c | 33 +++++++++++++-------
src/systemctl/systemctl.c | 28 +++++++++++++++++
4 files changed, 89 insertions(+), 39 deletions(-)
diff --git a/man/systemctl.xml b/man/systemctl.xml
index 1df0b158bd..cea6192224 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -1448,6 +1448,9 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<option>--force</option> is specified twice the halt operation is executed by <command>systemctl</command>
itself, and the system manager is not contacted. This means the command should succeed even when the system
manager has crashed.</para>
+
+ <para>If combined with <option>--when=</option>, shutdown will be scheduled after the given timestamp.
+ And <option>--when=cancel</option> will cancel the shutdown.</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -1459,13 +1462,8 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
users. This command is asynchronous; it will return after the power-off operation is enqueued, without
waiting for it to complete.</para>
- <para>If combined with <option>--force</option>, shutdown of all running services is skipped, however all
- processes are killed and all file systems are unmounted or mounted read-only, immediately followed by the
- powering off. If <option>--force</option> is specified twice, the operation is immediately executed without
- terminating any processes or unmounting any file systems. This may result in data loss. Note that when
- <option>--force</option> is specified twice the power-off operation is executed by
- <command>systemctl</command> itself, and the system manager is not contacted. This means the command should
- succeed even when the system manager has crashed.</para>
+ <para>This command honors <option>--force</option> and <option>--when=</option> in a similar way
+ as <command>halt</command>.</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -1479,14 +1477,6 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
users. This command is asynchronous; it will return after the reboot operation is enqueued,
without waiting for it to complete.</para>
- <para>If combined with <option>--force</option>, shutdown of all running services is skipped, however all
- processes are killed and all file systems are unmounted or mounted read-only, immediately followed by the
- reboot. If <option>--force</option> is specified twice, the operation is immediately executed without
- terminating any processes or unmounting any file systems. This may result in data loss. Note that when
- <option>--force</option> is specified twice the reboot operation is executed by
- <command>systemctl</command> itself, and the system manager is not contacted. This means the command should
- succeed even when the system manager has crashed.</para>
-
<para>If the switch <option>--reboot-argument=</option> is given, it will be passed as the optional
argument to the <citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
system call.</para>
@@ -1494,6 +1484,9 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<para>Options <option>--boot-loader-entry=</option>, <option>--boot-loader-menu=</option>, and
<option>--firmware-setup</option> can be used to select what to do <emphasis>after</emphasis> the
reboot. See the descriptions of those options for details.</para>
+
+ <para>This command honors <option>--force</option> and <option>--when=</option> in a similar way
+ as <command>halt</command>.</para>
</listitem>
</varlistentry>
@@ -1506,9 +1499,8 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
asynchronous; it will return after the reboot operation is enqueued, without waiting for it to
complete.</para>
- <para>If combined with <option>--force</option>, shutdown of all running services is skipped, however all
- processes are killed and all file systems are unmounted or mounted read-only, immediately followed by the
- reboot.</para>
+ <para>This command honors <option>--force</option> and <option>--when=</option> in a similar way
+ as <command>halt</command>.</para>
</listitem>
</varlistentry>
@@ -2420,6 +2412,19 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<listitem><para>When used with <command>bind</command>, creates a read-only bind mount.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--when=</option></term>
+
+ <listitem>
+ <para>When used with <command>halt</command>, <command>poweroff</command>, <command>reboot</command>
+ or <command>kexec</command>, schedule the action to be performed at the given timestamp,
+ which should adhere to the syntax documented in <citerefentry
+ project='man-pages'><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ section "PARSING TIMESTAMPS". Specially, if <literal>show</literal> is given, the currently scheduled
+ action will be shown, which can be canceled by passing an empty string or <literal>cancel</literal>.</para>
+ </listitem>
+ </varlistentry>
+
<xi:include href="user-system-options.xml" xpointer="host" />
<xi:include href="user-system-options.xml" xpointer="machine" />
diff --git a/src/systemctl/systemctl-logind.c b/src/systemctl/systemctl-logind.c
index 068f54e18b..fd8ca09de8 100644
--- a/src/systemctl/systemctl-logind.c
+++ b/src/systemctl/systemctl-logind.c
@@ -356,7 +356,7 @@ int logind_show_shutdown(void) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
sd_bus *bus;
- const char *action = NULL;
+ const char *action, *pretty_action;
uint64_t elapse;
int r;
@@ -376,17 +376,23 @@ int logind_show_shutdown(void) {
return log_error_errno(SYNTHETIC_ERRNO(ENODATA), "No scheduled shutdown.");
if (STR_IN_SET(action, "halt", "poweroff", "exit"))
- action = "Shutdown";
+ pretty_action = "Shutdown";
else if (streq(action, "kexec"))
- action = "Reboot via kexec";
+ pretty_action = "Reboot via kexec";
else if (streq(action, "reboot"))
- action = "Reboot";
-
- /* If we don't recognize the action string, we'll show it as-is */
-
- log_info("%s scheduled for %s, use 'shutdown -c' to cancel.",
- action,
- FORMAT_TIMESTAMP_STYLE(elapse, arg_timestamp_style));
+ pretty_action = "Reboot";
+ else /* If we don't recognize the action string, we'll show it as-is */
+ pretty_action = action;
+
+ if (arg_action == ACTION_SYSTEMCTL)
+ log_info("%s scheduled for %s, use 'systemctl %s --when=cancel' to cancel.",
+ pretty_action,
+ FORMAT_TIMESTAMP_STYLE(elapse, arg_timestamp_style),
+ action);
+ else
+ log_info("%s scheduled for %s, use 'shutdown -c' to cancel.",
+ pretty_action,
+ FORMAT_TIMESTAMP_STYLE(elapse, arg_timestamp_style));
return 0;
#else
diff --git a/src/systemctl/systemctl-start-special.c b/src/systemctl/systemctl-start-special.c
index 9363764cd7..4dee3028b0 100644
--- a/src/systemctl/systemctl-start-special.c
+++ b/src/systemctl/systemctl-start-special.c
@@ -208,22 +208,33 @@ int verb_start_special(int argc, char *argv[], void *userdata) {
ACTION_POWEROFF,
ACTION_REBOOT,
ACTION_KEXEC,
- ACTION_HALT,
- ACTION_SUSPEND,
- ACTION_HIBERNATE,
- ACTION_HYBRID_SLEEP,
- ACTION_SUSPEND_THEN_HIBERNATE)) {
-
- r = logind_reboot(a);
- if (r >= 0)
- return r;
- if (IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS))
- /* Requested operation requires auth, is not supported or already in progress */
+ ACTION_HALT)) {
+
+ if (arg_when == 0)
+ r = logind_reboot(a);
+ else if (arg_when != USEC_INFINITY)
+ r = logind_schedule_shutdown(a);
+ else /* arg_when == USEC_INFINITY */
+ r = logind_cancel_shutdown();
+ if (r >= 0 || IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS))
+ /* The latter indicates that the requested operation requires auth,
+ * is not supported or already in progress, in which cases we ignore the error. */
return r;
/* On all other errors, try low-level operation. In order to minimize the difference
* between operation with and without logind, we explicitly enable non-blocking mode
* for this, as logind's shutdown operations are always non-blocking. */
+ arg_no_block = true;
+
+ } else if (IN_SET(a,
+ ACTION_SUSPEND,
+ ACTION_HIBERNATE,
+ ACTION_HYBRID_SLEEP,
+ ACTION_SUSPEND_THEN_HIBERNATE)) {
+
+ r = logind_reboot(a);
+ if (r >= 0 || IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS))
+ return r;
arg_no_block = true;
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 883a5b75f4..9dfde28426 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -313,6 +313,8 @@ static int systemctl_help(void) {
" --read-only Create read-only bind mount\n"
" --mkdir Create directory before mounting, if missing\n"
" --marked Restart/reload previously marked units\n"
+ " --when=TIME Schedule halt/power-off/reboot/kexec action after\n"
+ " a certain timestamp\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
@@ -435,6 +437,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
ARG_MKDIR,
ARG_MARKED,
ARG_NO_WARN,
+ ARG_WHEN,
};
static const struct option options[] = {
@@ -497,6 +500,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{ "read-only", no_argument, NULL, ARG_READ_ONLY },
{ "mkdir", no_argument, NULL, ARG_MKDIR },
{ "marked", no_argument, NULL, ARG_MARKED },
+ { "when", required_argument, NULL, ARG_WHEN },
{}
};
@@ -933,6 +937,30 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
arg_no_warn = true;
break;
+ case ARG_WHEN:
+ if (streq(optarg, "show")) {
+ r = logind_show_shutdown();
+ if (r < 0 && r != -ENODATA)
+ return r;
+
+ return 0;
+ }
+
+ if (STR_IN_SET(optarg, "", "cancel")) {
+ arg_when = USEC_INFINITY;
+ break;
+ }
+
+ r = parse_timestamp(optarg, &arg_when);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --when= argument '%s': %m", optarg);
+
+ if (!timestamp_is_set(arg_when))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Invalid timestamp '%s' specified for --when=.", optarg);
+
+ break;
+
case '.':
/* Output an error mimicking getopt, and print a hint afterwards */
log_error("%s: invalid option -- '.'", program_invocation_name);

View File

@ -0,0 +1,31 @@
From e8f66d4c6570765fd60111ec7e3b5dbdb7d14c69 Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Tue, 14 Mar 2023 07:16:18 +0800
Subject: [PATCH] test-time-util: add test cases to invalidate "show" and
"cancel"
Ensure that systemctl reboot --when=show and --when=cancel will not result in ambiguities
(cherry picked from commit 165655cb1de2e79d954d9165459143140e52c53b)
Related: RHEL-109488
---
src/test/test-time-util.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c
index ee861135c2..379f55ff2f 100644
--- a/src/test/test-time-util.c
+++ b/src/test/test-time-util.c
@@ -580,6 +580,11 @@ static void test_parse_timestamp_one(const char *str, usec_t max_diff, usec_t ex
static void test_parse_timestamp_impl(const char *tz) {
usec_t today, now_usec;
+ /* Invalid: Ensure that systemctl reboot --when=show and --when=cancel
+ * will not result in ambiguities */
+ assert_se(parse_timestamp("show", NULL) == -EINVAL);
+ assert_se(parse_timestamp("cancel", NULL) == -EINVAL);
+
/* UTC */
test_parse_timestamp_one("Thu 1970-01-01 00:01 UTC", 0, USEC_PER_MINUTE);
test_parse_timestamp_one("Thu 1970-01-01 00:00:01 UTC", 0, USEC_PER_SEC);

View File

@ -0,0 +1,128 @@
From 5bec9826a14483e7e612879fe2630f1b517e37be Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sun, 9 Jul 2023 13:25:42 -0600
Subject: [PATCH] Introduce RET_GATHER and use it in src/shared/
The idea is to make it easier to implement the common pattern of
accumulating errors (negative values) in an accumulator to return
the first error.
(cherry picked from commit 809c3a84e1a572ccaaa7eca5394c0b842118c22f)
Resolves: RHEL-108598
---
src/basic/errno-util.h | 10 ++++++++++
src/shared/bus-util.c | 10 ++--------
src/shared/devnode-acl.c | 4 ++--
src/shared/nscd-flush.c | 16 +++++-----------
src/test/test-errno-util.c | 11 +++++++++++
5 files changed, 30 insertions(+), 21 deletions(-)
diff --git a/src/basic/errno-util.h b/src/basic/errno-util.h
index b10dd755c9..27804e6382 100644
--- a/src/basic/errno-util.h
+++ b/src/basic/errno-util.h
@@ -74,6 +74,16 @@ static inline int RET_NERRNO(int ret) {
return ret;
}
+/* Collect possible errors in <acc>, so that the first error can be returned.
+ * Returns (possibly updated) <acc>. */
+#define RET_GATHER(acc, err) \
+ ({ \
+ int *__a = &(acc), __e = (err); \
+ if (*__a >= 0 && __e < 0) \
+ *__a = __e; \
+ *__a; \
+ })
+
static inline int errno_or_else(int fallback) {
/* To be used when invoking library calls where errno handling is not defined clearly: we return
* errno if it is set, and the specified error otherwise. The idea is that the caller initializes
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 5e6d17d201..7c8d2aa6f5 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -484,14 +484,8 @@ int bus_track_add_name_many(sd_bus_track *t, char **l) {
/* Continues adding after failure, and returns the first failure. */
- STRV_FOREACH(i, l) {
- int k;
-
- k = sd_bus_track_add_name(t, *i);
- if (k < 0 && r >= 0)
- r = k;
- }
-
+ STRV_FOREACH(i, l)
+ RET_GATHER(r, sd_bus_track_add_name(t, *i));
return r;
}
diff --git a/src/shared/devnode-acl.c b/src/shared/devnode-acl.c
index 66e3a40f2f..8c961061cf 100644
--- a/src/shared/devnode-acl.c
+++ b/src/shared/devnode-acl.c
@@ -220,8 +220,8 @@ int devnode_acl_all(const char *seat,
k = devnode_acl(n, flush, del, old_uid, add, new_uid);
if (k == -ENOENT)
log_debug("Device %s disappeared while setting ACLs", n);
- else if (k < 0 && r == 0)
- r = k;
+ else
+ RET_GATHER(r, k);
}
return r;
diff --git a/src/shared/nscd-flush.c b/src/shared/nscd-flush.c
index 9b0ba2d67a..d2b41f2b4d 100644
--- a/src/shared/nscd-flush.c
+++ b/src/shared/nscd-flush.c
@@ -128,21 +128,15 @@ static int nscd_flush_cache_one(const char *database, usec_t end) {
}
int nscd_flush_cache(char **databases) {
- usec_t end;
int r = 0;
- /* Tries to invalidate the specified database in nscd. We do this carefully, with a 5s timeout, so that we
- * don't block indefinitely on another service. */
+ /* Tries to invalidate the specified database in nscd. We do this carefully, with a 5s timeout,
+ * so that we don't block indefinitely on another service. */
- end = usec_add(now(CLOCK_MONOTONIC), NSCD_FLUSH_CACHE_TIMEOUT_USEC);
+ usec_t end = usec_add(now(CLOCK_MONOTONIC), NSCD_FLUSH_CACHE_TIMEOUT_USEC);
- STRV_FOREACH(i, databases) {
- int k;
-
- k = nscd_flush_cache_one(*i, end);
- if (k < 0 && r >= 0)
- r = k;
- }
+ STRV_FOREACH(i, databases)
+ RET_GATHER(r, nscd_flush_cache_one(*i, end));
return r;
}
diff --git a/src/test/test-errno-util.c b/src/test/test-errno-util.c
index cac0d5402b..77fb7d0011 100644
--- a/src/test/test-errno-util.c
+++ b/src/test/test-errno-util.c
@@ -67,4 +67,15 @@ TEST(ERRNO_IS_TRANSIENT) {
assert_se(!ERRNO_IS_NEG_TRANSIENT(INTMAX_MIN));
}
+TEST(RET_GATHER) {
+ int x = 0, y = 2;
+
+ assert_se(RET_GATHER(x, 5) == 0);
+ assert_se(RET_GATHER(x, -5) == -5);
+ assert_se(RET_GATHER(x, -1) == -5);
+
+ assert_se(RET_GATHER(x, y++) == -5);
+ assert_se(y == 3);
+}
+
DEFINE_TEST_MAIN(LOG_INFO);

View File

@ -0,0 +1,50 @@
From c2dc44abd4014f13a40dde350af92e2d74201359 Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Fri, 29 Dec 2023 17:57:59 +0800
Subject: [PATCH] fd-util: don't eat up errors in fd_cloexec_many
Follow-up for ed18c22c989495aab36512f03449222cfcf79aa7
Before this commit, a successful fd_cloexec() call would
discard all previously gathered errors.
(cherry picked from commit 6b9cac874c33f4fa27aa4b4b5b980f60c28ee043)
Resolves: RHEL-108598
---
src/basic/fd-util.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c
index 66bb7569bb..932c5a8d80 100644
--- a/src/basic/fd-util.c
+++ b/src/basic/fd-util.c
@@ -175,7 +175,7 @@ int fd_cloexec(int fd, bool cloexec) {
}
int fd_cloexec_many(const int fds[], size_t n_fds, bool cloexec) {
- int ret = 0, r;
+ int r = 0;
assert(n_fds == 0 || fds);
@@ -183,14 +183,13 @@ int fd_cloexec_many(const int fds[], size_t n_fds, bool cloexec) {
if (fds[i] < 0) /* Skip gracefully over already invalidated fds */
continue;
- r = fd_cloexec(fds[i], cloexec);
- if (r < 0 && ret >= 0) /* Continue going, but return first error */
- ret = r;
- else
- ret = 1; /* report if we did anything */
+ RET_GATHER(r, fd_cloexec(fds[i], cloexec));
+
+ if (r >= 0)
+ r = 1; /* report if we did anything */
}
- return ret;
+ return r;
}
_pure_ static bool fd_in_set(int fd, const int fdset[], size_t n_fdset) {

View File

@ -0,0 +1,52 @@
From 762a8dc0c328e256847b111249bbff8e70f98942 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 19 May 2023 04:33:39 +0900
Subject: [PATCH] sd-bus: refuse to send messages with an invalid string
Prompted by aaf7b0e41105d7b7cf30912cdac32820f011a219 and
4804da58536ab7ad46178a03f4d2da49fd8e4ba2.
(cherry picked from commit 26a9dd6f55bb757e0033995cbb16bca12986b7cd)
Resolves: RHEL-108584
---
src/libsystemd/sd-bus/bus-message.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c
index 213b276e33..c51af56dda 100644
--- a/src/libsystemd/sd-bus/bus-message.c
+++ b/src/libsystemd/sd-bus/bus-message.c
@@ -1324,12 +1324,21 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void
* into the empty string */
p = strempty(p);
- _fallthrough_;
+ if (!utf8_is_valid(p))
+ return -EINVAL;
+
+ align = 4;
+ sz = 4 + strlen(p) + 1;
+ break;
+
case SD_BUS_TYPE_OBJECT_PATH:
if (!p)
return -EINVAL;
+ if (!object_path_is_valid(p))
+ return -EINVAL;
+
align = 4;
sz = 4 + strlen(p) + 1;
break;
@@ -1338,6 +1347,9 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void
p = strempty(p);
+ if (!signature_is_valid(p, /* allow_dict_entry = */ true))
+ return -EINVAL;
+
align = 1;
sz = 1 + strlen(p) + 1;
break;

View File

@ -0,0 +1,92 @@
From f3f939b236636fdca38e89ca564a669f0da4fd4d Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Fri, 19 May 2023 18:42:36 +0200
Subject: [PATCH] test: check if we correctly handle invalid UTF-8 in mount
stuff
Provides coverage for #27611.
(cherry picked from commit b74df879fc81d4668ce14532a76c23b85e651170)
Resolves: RHEL-108584
---
.../units/testsuite-07.mount-invalid-chars.sh | 70 +++++++++++++++++++
1 file changed, 70 insertions(+)
create mode 100755 test/units/testsuite-07.mount-invalid-chars.sh
diff --git a/test/units/testsuite-07.mount-invalid-chars.sh b/test/units/testsuite-07.mount-invalid-chars.sh
new file mode 100755
index 0000000000..617ea697c8
--- /dev/null
+++ b/test/units/testsuite-07.mount-invalid-chars.sh
@@ -0,0 +1,70 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -eux
+set -o pipefail
+
+# Don't send invalid characters over dbus if a mount contains them
+
+at_exit() {
+ mountpoint -q /proc/1/mountinfo && umount /proc/1/mountinfo
+ [[ -e /tmp/fstab.bak ]] && mv -f /tmp/fstab /etc/fstab
+ rm -f /run/systemd/system/foo-*.mount
+ systemctl daemon-reload
+}
+
+trap at_exit EXIT
+
+# Check invalid characters directly in /proc/mountinfo
+#
+# This is a bit tricky (and hacky), since we have to temporarily replace
+# PID 1's /proc/mountinfo, but we have to keep the original mounts intact,
+# otherwise systemd would unmount them on reload
+TMP_MOUNTINFO="$(mktemp)"
+
+cp /proc/1/mountinfo "$TMP_MOUNTINFO"
+# Add a mount entry with a "Unicode non-character" in it
+echo -ne '69 1 252:2 / /foo/mountinfo rw,relatime shared:1 - cifs //foo\ufffebar rw,seclabel\n' >>"$TMP_MOUNTINFO"
+mount --bind "$TMP_MOUNTINFO" /proc/1/mountinfo
+systemctl daemon-reload
+# On affected versions this would throw an error:
+# Failed to get properties: Bad message
+systemctl status foo-mountinfo.mount
+
+umount /proc/1/mountinfo
+systemctl daemon-reload
+rm -f "$TMP_MOUNTINFO"
+
+# Check invalid characters in a mount unit
+#
+# systemd already handles this and refuses to load the invalid string, e.g.:
+# foo-fstab.mount:9: String is not UTF-8 clean, ignoring assignment: What=//localhost/foo<6F><6F><EFBFBD>bar
+#
+# a) Unit generated from /etc/fstab
+[[ -e /etc/fstab ]] && cp -f /etc/fstab /tmp/fstab.bak
+
+echo -ne '//localhost/foo\ufffebar /foo/fstab cifs defaults 0 0\n' >/etc/fstab
+systemctl daemon-reload
+[[ "$(systemctl show -P UnitFileState foo-fstab.mount)" == bad ]]
+
+# b) Unit generated from /etc/fstab (but the invalid character is in options)
+echo -ne '//localhost/foobar /foo/fstab/opt cifs nosuid,a\ufffeb,noexec 0 0\n' >/etc/fstab
+systemctl daemon-reload
+[[ "$(systemctl show -P UnitFileState foo-fstab-opt.mount)" == bad ]]
+rm -f /etc/fstab
+
+[[ -e /tmp/fstab.bak ]] && mv -f /tmp/fstab /etc/fstab
+systemctl daemon-reload
+
+# c) Mount unit
+mkdir -p /run/systemd/system
+echo -ne '[Mount]\nWhat=//localhost/foo\ufffebar\nWhere=/foo/unit\nType=cifs\nOptions=noexec\n' >/run/systemd/system/foo-unit.mount
+systemctl daemon-reload
+[[ "$(systemctl show -P UnitFileState foo-unit.mount)" == bad ]]
+rm -f /run/systemd/system/foo-unit.mount
+
+# d) Mount unit (but the invalid character is in Options=)
+mkdir -p /run/systemd/system
+echo -ne '[Mount]\nWhat=//localhost/foobar\nWhere=/foo/unit/opt\nType=cifs\nOptions=noexec,a\ufffeb,nosuid\n' >/run/systemd/system/foo-unit-opt.mount
+systemctl daemon-reload
+[[ "$(systemctl show -P UnitFileState foo-unit-opt.mount)" == bad ]]
+rm -f /run/systemd/system/foo-unit-opt.mount

View File

@ -0,0 +1,25 @@
From e882eabc5c9115413db1e6d83f4542ad618fec23 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Mon, 22 May 2023 12:06:16 +0200
Subject: [PATCH] test: fix a typo in the cleanup stuff
(cherry picked from commit 7942811255f3d6973b246ebf6b26b690bbceab37)
Resolves: RHEL-108584
---
test/units/testsuite-07.mount-invalid-chars.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/units/testsuite-07.mount-invalid-chars.sh b/test/units/testsuite-07.mount-invalid-chars.sh
index 617ea697c8..b70e621126 100755
--- a/test/units/testsuite-07.mount-invalid-chars.sh
+++ b/test/units/testsuite-07.mount-invalid-chars.sh
@@ -7,7 +7,7 @@ set -o pipefail
at_exit() {
mountpoint -q /proc/1/mountinfo && umount /proc/1/mountinfo
- [[ -e /tmp/fstab.bak ]] && mv -f /tmp/fstab /etc/fstab
+ [[ -e /tmp/fstab.bak ]] && mv -f /tmp/fstab.bak /etc/fstab
rm -f /run/systemd/system/foo-*.mount
systemctl daemon-reload
}

View File

@ -0,0 +1,62 @@
From 78641d8a552eb95dd85cad9686d829af48478727 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Mon, 14 Aug 2023 20:09:31 +0200
Subject: [PATCH] test: explicitly specify a UTF-8 locale for UTF-8 shenanigans
As things don't work well without it:
$ LANG=C printf "\ufffe\n"
\uFFFE
(cherry picked from commit 01febfcdce0326aa1888d085c1009c9399f6a930)
Resolves: RHEL-108584
---
test/units/testsuite-07.mount-invalid-chars.sh | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/test/units/testsuite-07.mount-invalid-chars.sh b/test/units/testsuite-07.mount-invalid-chars.sh
index b70e621126..5a07d14d04 100755
--- a/test/units/testsuite-07.mount-invalid-chars.sh
+++ b/test/units/testsuite-07.mount-invalid-chars.sh
@@ -23,7 +23,7 @@ TMP_MOUNTINFO="$(mktemp)"
cp /proc/1/mountinfo "$TMP_MOUNTINFO"
# Add a mount entry with a "Unicode non-character" in it
-echo -ne '69 1 252:2 / /foo/mountinfo rw,relatime shared:1 - cifs //foo\ufffebar rw,seclabel\n' >>"$TMP_MOUNTINFO"
+LANG="C.UTF-8" printf '69 1 252:2 / /foo/mountinfo rw,relatime shared:1 - cifs //foo\ufffebar rw,seclabel\n' >>"$TMP_MOUNTINFO"
mount --bind "$TMP_MOUNTINFO" /proc/1/mountinfo
systemctl daemon-reload
# On affected versions this would throw an error:
@@ -42,12 +42,12 @@ rm -f "$TMP_MOUNTINFO"
# a) Unit generated from /etc/fstab
[[ -e /etc/fstab ]] && cp -f /etc/fstab /tmp/fstab.bak
-echo -ne '//localhost/foo\ufffebar /foo/fstab cifs defaults 0 0\n' >/etc/fstab
+LANG="C.UTF-8" printf '//localhost/foo\ufffebar /foo/fstab cifs defaults 0 0\n' >/etc/fstab
systemctl daemon-reload
[[ "$(systemctl show -P UnitFileState foo-fstab.mount)" == bad ]]
# b) Unit generated from /etc/fstab (but the invalid character is in options)
-echo -ne '//localhost/foobar /foo/fstab/opt cifs nosuid,a\ufffeb,noexec 0 0\n' >/etc/fstab
+LANG="C.UTF-8" printf '//localhost/foobar /foo/fstab/opt cifs nosuid,a\ufffeb,noexec 0 0\n' >/etc/fstab
systemctl daemon-reload
[[ "$(systemctl show -P UnitFileState foo-fstab-opt.mount)" == bad ]]
rm -f /etc/fstab
@@ -57,14 +57,14 @@ systemctl daemon-reload
# c) Mount unit
mkdir -p /run/systemd/system
-echo -ne '[Mount]\nWhat=//localhost/foo\ufffebar\nWhere=/foo/unit\nType=cifs\nOptions=noexec\n' >/run/systemd/system/foo-unit.mount
+LANG="C.UTF-8" printf '[Mount]\nWhat=//localhost/foo\ufffebar\nWhere=/foo/unit\nType=cifs\nOptions=noexec\n' >/run/systemd/system/foo-unit.mount
systemctl daemon-reload
[[ "$(systemctl show -P UnitFileState foo-unit.mount)" == bad ]]
rm -f /run/systemd/system/foo-unit.mount
# d) Mount unit (but the invalid character is in Options=)
mkdir -p /run/systemd/system
-echo -ne '[Mount]\nWhat=//localhost/foobar\nWhere=/foo/unit/opt\nType=cifs\nOptions=noexec,a\ufffeb,nosuid\n' >/run/systemd/system/foo-unit-opt.mount
+LANG="C.UTF-8" printf '[Mount]\nWhat=//localhost/foobar\nWhere=/foo/unit/opt\nType=cifs\nOptions=noexec,a\ufffeb,nosuid\n' >/run/systemd/system/foo-unit-opt.mount
systemctl daemon-reload
[[ "$(systemctl show -P UnitFileState foo-unit-opt.mount)" == bad ]]
rm -f /run/systemd/system/foo-unit-opt.mount

View File

@ -0,0 +1,26 @@
From 15ad0f0a0145640ee290d805030338f8c01051f4 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Wed, 23 Aug 2023 15:10:23 +0200
Subject: [PATCH] test: use the correct file name when restoring the original
fstab
(cherry picked from commit 9541addff028b56724df79fcf5b88e1544403957)
Resolves: RHEL-108584
---
test/units/testsuite-07.mount-invalid-chars.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/units/testsuite-07.mount-invalid-chars.sh b/test/units/testsuite-07.mount-invalid-chars.sh
index 5a07d14d04..a879334869 100755
--- a/test/units/testsuite-07.mount-invalid-chars.sh
+++ b/test/units/testsuite-07.mount-invalid-chars.sh
@@ -52,7 +52,7 @@ systemctl daemon-reload
[[ "$(systemctl show -P UnitFileState foo-fstab-opt.mount)" == bad ]]
rm -f /etc/fstab
-[[ -e /tmp/fstab.bak ]] && mv -f /tmp/fstab /etc/fstab
+[[ -e /tmp/fstab.bak ]] && mv -f /tmp/fstab.bak /etc/fstab
systemctl daemon-reload
# c) Mount unit

View File

@ -0,0 +1,134 @@
From b280191167ddc52a77da5b4047297d288f9ce73b Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 20 Jun 2025 13:16:10 +0200
Subject: [PATCH] core: escape UTF-8 in mount unit Where field before sending
to clients
Followup for: 4804da58536ab7ad46178a03f4d2da49fd8e4ba2 #27541
Fixes: #36206
(cherry picked from commit 222b0b05ce9ac29283cd89cf98444c4da3373568)
Resolves: RHEL-108584
---
src/core/dbus-mount.c | 23 ++++++++++++++++++-
src/core/mount.c | 16 ++++++++++++-
src/core/mount.h | 2 ++
.../units/testsuite-07.mount-invalid-chars.sh | 5 ++--
4 files changed, 42 insertions(+), 4 deletions(-)
diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c
index 55ad4f2c98..7006ebbbba 100644
--- a/src/core/dbus-mount.c
+++ b/src/core/dbus-mount.c
@@ -11,6 +11,27 @@
#include "unit.h"
#include "utf8.h"
+static int property_get_where(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Mount *m = ASSERT_PTR(userdata);
+
+ assert(bus);
+ assert(reply);
+
+ _cleanup_free_ char *escaped = mount_get_where_escaped(m);
+ if (!escaped)
+ return -ENOMEM;
+
+ return sd_bus_message_append_basic(reply, 's', escaped);
+}
+
static int property_get_what(
sd_bus *bus,
const char *path,
@@ -84,7 +105,7 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, mount_result, MountResu
const sd_bus_vtable bus_mount_vtable[] = {
SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("Where", "s", NULL, offsetof(Mount, where), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Where", "s", property_get_where, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("What", "s", property_get_what, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Options","s", property_get_options, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Type", "s", property_get_type, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
diff --git a/src/core/mount.c b/src/core/mount.c
index cfe3f40302..79772fb6f1 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -31,6 +31,7 @@
#include "strv.h"
#include "unit-name.h"
#include "unit.h"
+#include "utf8.h"
#define RETRY_UMOUNT_MAX 32
@@ -657,7 +658,11 @@ static int mount_add_extras(Mount *m) {
path_simplify(m->where);
if (!u->description) {
- r = unit_set_description(u, m->where);
+ _cleanup_free_ char *w = mount_get_where_escaped(m);
+ if (!w)
+ return log_oom();
+
+ r = unit_set_description(u, w);
if (r < 0)
return r;
}
@@ -2207,6 +2212,15 @@ static int mount_can_start(Unit *u) {
return 1;
}
+char* mount_get_where_escaped(const Mount *m) {
+ assert(m);
+
+ if (!m->where)
+ return strdup("");
+
+ return utf8_escape_invalid(m->where);
+}
+
static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
[MOUNT_EXEC_MOUNT] = "ExecMount",
[MOUNT_EXEC_UNMOUNT] = "ExecUnmount",
diff --git a/src/core/mount.h b/src/core/mount.h
index 1a0d9fc5e5..db4a915202 100644
--- a/src/core/mount.h
+++ b/src/core/mount.h
@@ -93,6 +93,8 @@ extern const UnitVTable mount_vtable;
void mount_fd_event(Manager *m, int events);
+char* mount_get_where_escaped(const Mount *m);
+
const char* mount_exec_command_to_string(MountExecCommand i) _const_;
MountExecCommand mount_exec_command_from_string(const char *s) _pure_;
diff --git a/test/units/testsuite-07.mount-invalid-chars.sh b/test/units/testsuite-07.mount-invalid-chars.sh
index a879334869..cd2ca78fdf 100755
--- a/test/units/testsuite-07.mount-invalid-chars.sh
+++ b/test/units/testsuite-07.mount-invalid-chars.sh
@@ -23,12 +23,13 @@ TMP_MOUNTINFO="$(mktemp)"
cp /proc/1/mountinfo "$TMP_MOUNTINFO"
# Add a mount entry with a "Unicode non-character" in it
-LANG="C.UTF-8" printf '69 1 252:2 / /foo/mountinfo rw,relatime shared:1 - cifs //foo\ufffebar rw,seclabel\n' >>"$TMP_MOUNTINFO"
+LANG="C.UTF-8" printf '69 1 252:2 / /foo/mount\ufffeinfo rw,relatime shared:1 - cifs //foo\ufffebar rw,seclabel\n' >>"$TMP_MOUNTINFO"
mount --bind "$TMP_MOUNTINFO" /proc/1/mountinfo
systemctl daemon-reload
# On affected versions this would throw an error:
# Failed to get properties: Bad message
-systemctl status foo-mountinfo.mount
+systemctl list-units -t mount
+systemctl status foo-mount\\xef\\xbf\\xbeinfo.mount
umount /proc/1/mountinfo
systemctl daemon-reload

View File

@ -0,0 +1,51 @@
From 4d4f5e617bb467be81274dc32b7066fc5ce52b75 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <fsumsal@redhat.com>
Date: Wed, 3 Sep 2025 13:55:00 +0200
Subject: [PATCH] Revert "test-time-util: disable failing tests"
This won't be needed anymore.
This reverts commit c7a62e108ffbe41ccf1bb5fba4b5a37daf317939.
rhel-only: ci
Related: RHEL-109488
---
src/test/test-time-util.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c
index 379f55ff2f..56a71ecfba 100644
--- a/src/test/test-time-util.c
+++ b/src/test/test-time-util.c
@@ -698,7 +698,6 @@ static void test_parse_timestamp_impl(const char *tz) {
test_parse_timestamp_one("69-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000);
}
-#if 0
/* -06 */
test_parse_timestamp_one("Wed 1969-12-31 18:01 -06", 0, USEC_PER_MINUTE);
test_parse_timestamp_one("Wed 1969-12-31 18:00:01 -06", 0, USEC_PER_SEC);
@@ -761,7 +760,6 @@ static void test_parse_timestamp_impl(const char *tz) {
test_parse_timestamp_one("69-12-31 18:00:01 -06:00", 0, USEC_PER_SEC);
test_parse_timestamp_one("69-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000);
test_parse_timestamp_one("69-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000);
-#endif
/* without date */
assert_se(parse_timestamp("today", &today) == 0);
@@ -977,7 +975,6 @@ TEST(timezone_offset_change) {
test_timezone_offset_change_one("Sun 2018-10-28 02:00:00 UTC", "Sun 2018-10-28 03:00:00 +01");
}
-#if 0
if (timezone_is_valid("Asia/Atyrau", LOG_DEBUG)) {
assert_se(setenv("TZ", ":Asia/Atyrau", 1) >= 0);
tzset();
@@ -999,7 +996,6 @@ TEST(timezone_offset_change) {
test_timezone_offset_change_one("Sun 1982-03-14 02:59:59 UTC", "Sat 1982-03-13 20:59:59 -06");
test_timezone_offset_change_one("Sun 1982-03-14 03:00:00 UTC", "Sat 1982-03-13 21:00:00 -06");
}
-#endif
assert_se(set_unset_env("TZ", tz, true) == 0);
tzset();

View File

@ -0,0 +1,92 @@
From 03dff755efde1a311969636e11fe95c398b7d878 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 3 Mar 2023 19:40:40 +0900
Subject: [PATCH] test: use get_timezones() to iterate all known timezones
(cherry picked from commit 0b20d70d1c7c190fb943dd4d1f28e6f456d2193e)
Related: RHEL-109488
---
src/test/test-time-util.c | 50 +++++++++------------------------------
1 file changed, 11 insertions(+), 39 deletions(-)
diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c
index 56a71ecfba..eb8cc538c0 100644
--- a/src/test/test-time-util.c
+++ b/src/test/test-time-util.c
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#include "dirent-util.h"
#include "env-util.h"
#include "fd-util.h"
#include "fileio.h"
@@ -414,23 +413,18 @@ TEST(FORMAT_TIMESTAMP) {
test_format_timestamp_loop();
}
-static void test_format_timestamp_with_tz_one(const char *name1, const char *name2) {
- _cleanup_free_ char *buf = NULL, *tz = NULL;
- const char *name, *saved_tz;
-
- if (name2)
- assert_se(buf = path_join(name1, name2));
- name = buf ?: name1;
+static void test_format_timestamp_with_tz_one(const char *tz) {
+ const char *saved_tz, *colon_tz;
- if (!timezone_is_valid(name, LOG_DEBUG))
+ if (!timezone_is_valid(tz, LOG_DEBUG))
return;
- log_info("/* %s(%s) */", __func__, name);
+ log_info("/* %s(%s) */", __func__, tz);
saved_tz = getenv("TZ");
- assert_se(tz = strjoin(":", name));
- assert_se(setenv("TZ", tz, 1) >= 0);
+ assert_se(colon_tz = strjoina(":", tz));
+ assert_se(setenv("TZ", colon_tz, 1) >= 0);
tzset();
log_debug("%s: tzname[0]=%s, tzname[1]=%s", tz, strempty(tzname[0]), strempty(tzname[1]));
@@ -441,33 +435,11 @@ static void test_format_timestamp_with_tz_one(const char *name1, const char *nam
}
TEST(FORMAT_TIMESTAMP_with_tz) {
- if (!slow_tests_enabled())
- return (void) log_tests_skipped("slow tests are disabled");
-
- _cleanup_closedir_ DIR *dir = opendir("/usr/share/zoneinfo");
- if (!dir)
- return (void) log_tests_skipped_errno(errno, "Failed to open /usr/share/zoneinfo");
-
- FOREACH_DIRENT(de, dir, break) {
- if (de->d_type == DT_REG)
- test_format_timestamp_with_tz_one(de->d_name, NULL);
-
- else if (de->d_type == DT_DIR) {
- if (streq(de->d_name, "right"))
- /* The test does not support timezone with leap second info. */
- continue;
-
- _cleanup_closedir_ DIR *subdir = xopendirat(dirfd(dir), de->d_name, 0);
- if (!subdir) {
- log_notice_errno(errno, "Failed to open /usr/share/zoneinfo/%s, ignoring: %m", de->d_name);
- continue;
- }
-
- FOREACH_DIRENT(subde, subdir, break)
- if (subde->d_type == DT_REG)
- test_format_timestamp_with_tz_one(de->d_name, subde->d_name);
- }
- }
+ _cleanup_strv_free_ char **timezones = NULL;
+
+ assert_se(get_timezones(&timezones) >= 0);
+ STRV_FOREACH(tz, timezones)
+ test_format_timestamp_with_tz_one(*tz);
}
TEST(format_timestamp_relative) {

View File

@ -0,0 +1,72 @@
From c1e4badeadf75e75b6059a6d644d28414013c102 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 13 Mar 2023 03:47:45 +0900
Subject: [PATCH] test-time-util: do not fail on DST change
(cherry picked from commit cfacd245e798282fcb9b3231bd6e857abfe124fc)
Related: RHEL-109488
---
src/test/test-time-util.c | 37 ++++++++++++++++++++++++++++++-------
1 file changed, 30 insertions(+), 7 deletions(-)
diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c
index eb8cc538c0..775e6bb84a 100644
--- a/src/test/test-time-util.c
+++ b/src/test/test-time-util.c
@@ -543,12 +543,30 @@ static void test_parse_timestamp_one(const char *str, usec_t max_diff, usec_t ex
int r;
r = parse_timestamp(str, &usec);
- log_debug("/* %s(%s): max_diff="USEC_FMT", expected="USEC_FMT", result="USEC_FMT"*/", __func__, str, max_diff, expected, usec);
+ log_debug("/* %s(%s): max_diff="USEC_FMT", expected="USEC_FMT", result="USEC_FMT" */", __func__, str, max_diff, expected, usec);
assert_se(r >= 0);
assert_se(usec >= expected);
assert_se(usec_sub_unsigned(usec, expected) <= max_diff);
}
+static bool time_is_zero(usec_t usec) {
+ const char *s;
+
+ s = FORMAT_TIMESTAMP(usec);
+ return strstr(s, " 00:00:00 ");
+}
+
+static bool timezone_equal(usec_t today, usec_t target) {
+ const char *s, *t, *sz, *tz;
+
+ s = FORMAT_TIMESTAMP(today);
+ t = FORMAT_TIMESTAMP(target);
+ assert_se(sz = strrchr(s, ' '));
+ assert_se(tz = strrchr(t, ' '));
+ log_debug("%s("USEC_FMT", "USEC_FMT") -> %s, %s", __func__, today, target, s, t);
+ return streq(sz, tz);
+}
+
static void test_parse_timestamp_impl(const char *tz) {
usec_t today, now_usec;
@@ -735,12 +753,17 @@ static void test_parse_timestamp_impl(const char *tz) {
/* without date */
assert_se(parse_timestamp("today", &today) == 0);
- test_parse_timestamp_one("00:01", 0, today + USEC_PER_MINUTE);
- test_parse_timestamp_one("00:00:01", 0, today + USEC_PER_SEC);
- test_parse_timestamp_one("00:00:01.001", 0, today + USEC_PER_SEC + 1000);
- test_parse_timestamp_one("00:00:01.0010", 0, today + USEC_PER_SEC + 1000);
- test_parse_timestamp_one("tomorrow", 0, today + USEC_PER_DAY);
- test_parse_timestamp_one("yesterday", 0, today - USEC_PER_DAY);
+ if (time_is_zero(today)) {
+ test_parse_timestamp_one("00:01", 0, today + USEC_PER_MINUTE);
+ test_parse_timestamp_one("00:00:01", 0, today + USEC_PER_SEC);
+ test_parse_timestamp_one("00:00:01.001", 0, today + USEC_PER_SEC + 1000);
+ test_parse_timestamp_one("00:00:01.0010", 0, today + USEC_PER_SEC + 1000);
+
+ if (timezone_equal(today, today + USEC_PER_DAY) && time_is_zero(today + USEC_PER_DAY))
+ test_parse_timestamp_one("tomorrow", 0, today + USEC_PER_DAY);
+ if (timezone_equal(today, today - USEC_PER_DAY) && time_is_zero(today - USEC_PER_DAY))
+ test_parse_timestamp_one("yesterday", 0, today - USEC_PER_DAY);
+ }
/* relative */
assert_se(parse_timestamp("now", &now_usec) == 0);

View File

@ -0,0 +1,82 @@
From 8e8569467616ee982df2cc73ac39240482c92d36 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sun, 26 Nov 2023 20:58:43 +0100
Subject: [PATCH] test-time-util: suppress timestamp conversion failures for
Africa/Khartoum timezone
Our timestamp conversion roundtrip test was failing. But I think that this
is not our bug:
$ TZ='Africa/Khartoum' date --date='@1509482094'
Tue Oct 31 23:34:54 EAT 2017
$ TZ='Africa/Khartoum' date --date='Tue Oct 31 23:34:54 EAT 2017' +%s
1509485694
$ TZ='Africa/Khartoum' date --date='@1509485694'
Tue Oct 31 23:34:54 CAT 2017
$ echo $[1509485694 - 1509482094]
3600
This is essentially the same as what happens in our test. After a round-trip, we
end up one hour ahead.
> For 1509482094632752, from the change log of tzdata:
>
> Release 2017c - 2017-10-20 14:49:34 -0700
>
> Changes to future timestamps
> Sudan will switch from +03 to +02 on 2017-11-01.
Fixes https://github.com/systemd/systemd/issues/28472.
(cherry picked from commit 78b95ccad864e1f993fe0776841dd8f39856581b)
Related: RHEL-109488
---
src/test/test-time-util.c | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c
index 775e6bb84a..2550ffdba2 100644
--- a/src/test/test-time-util.c
+++ b/src/test/test-time-util.c
@@ -382,7 +382,7 @@ TEST(format_timestamp) {
}
static void test_format_timestamp_impl(usec_t x) {
- bool success;
+ bool success, override;
const char *xx, *yy;
usec_t y;
@@ -393,14 +393,28 @@ static void test_format_timestamp_impl(usec_t x) {
assert_se(yy);
success = (x / USEC_PER_SEC == y / USEC_PER_SEC) && streq(xx, yy);
- log_full(success ? LOG_DEBUG : LOG_ERR, "@" USEC_FMT " → %s → @" USEC_FMT " → %s", x, xx, y, yy);
- assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
- assert_se(streq(xx, yy));
+ /* Workaround for https://github.com/systemd/systemd/issues/28472 */
+ override = !success &&
+ (STRPTR_IN_SET(tzname[0], "CAT", "EAT") ||
+ STRPTR_IN_SET(tzname[1], "CAT", "EAT")) &&
+ DIV_ROUND_UP(y - x, USEC_PER_SEC) == 3600; /* 1 hour, ignore fractional second */
+ log_full(success ? LOG_DEBUG : override ? LOG_WARNING : LOG_ERR,
+ "@" USEC_FMT " → %s → @" USEC_FMT " → %s%s",
+ x, xx, y, yy,
+ override ? ", ignoring." : "");
+ if (!override) {
+ assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
+ assert_se(streq(xx, yy));
+ }
}
static void test_format_timestamp_loop(void) {
test_format_timestamp_impl(USEC_PER_SEC);
+ /* Two cases which trigger https://github.com/systemd/systemd/issues/28472 */
+ test_format_timestamp_impl(1504938962980066);
+ test_format_timestamp_impl(1509482094632752);
+
for (unsigned i = 0; i < TRIAL; i++) {
usec_t x;

View File

@ -0,0 +1,68 @@
From 846cb844c3e8b5621745798f62bfbfb4275735f1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Thu, 5 Dec 2024 13:32:19 +0100
Subject: [PATCH] test-time-util: do more suppression of time zone checks
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The issue is directly triggered by tzdata-2024b, where the setting of timezone
started to fail and the tests stopped passing. But those timestamps in 1/1/1970
appear to have some problems already before:
$ sudo date -s 'Thu 1970-01-01 13:00:01 WET'
Thu Jan 1 03:00:01 PM EET 1970
$ sudo date -s 'Thu 1970-01-01 12:00:01 WET'
date: cannot set date: Invalid argument
Thu Jan 1 02:00:01 PM EET 1970
$ rpm -q tzdata
tzdata-2024a-9.fc41.noarch
The same issue appears with other timezones. So move the first timestamp one
day forward to avoid the issue.
After the previous problem is solved, we also get the problem already seen
previously where the roundtrip returns a time that is off by one hour:
@86401000000 → Fri 1970-01-02 00:00:01 WET → @82801000000 → Thu 1970-01-01 23:00:01 WET
Assertion 'x / USEC_PER_SEC == y / USEC_PER_SEC' failed at src/test/test-time-util.c:415, function test_format_timestamp_impl(). Aborting.
Extend the override to suppress this.
(cherry picked from commit 3cf362f6f57b7d0b5f6b86a49316303b0dda7599)
Related: RHEL-109488
---
src/test/test-time-util.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c
index 2550ffdba2..45d7541415 100644
--- a/src/test/test-time-util.c
+++ b/src/test/test-time-util.c
@@ -393,11 +393,12 @@ static void test_format_timestamp_impl(usec_t x) {
assert_se(yy);
success = (x / USEC_PER_SEC == y / USEC_PER_SEC) && streq(xx, yy);
- /* Workaround for https://github.com/systemd/systemd/issues/28472 */
+ /* Workaround for https://github.com/systemd/systemd/issues/28472
+ * and https://github.com/systemd/systemd/pull/35471. */
override = !success &&
- (STRPTR_IN_SET(tzname[0], "CAT", "EAT") ||
- STRPTR_IN_SET(tzname[1], "CAT", "EAT")) &&
- DIV_ROUND_UP(y - x, USEC_PER_SEC) == 3600; /* 1 hour, ignore fractional second */
+ (STRPTR_IN_SET(tzname[0], "CAT", "EAT", "WET") ||
+ STRPTR_IN_SET(tzname[1], "CAT", "EAT", "WET")) &&
+ DIV_ROUND_UP(x > y ? x - y : y - x, USEC_PER_SEC) == 3600; /* 1 hour, ignore fractional second */
log_full(success ? LOG_DEBUG : override ? LOG_WARNING : LOG_ERR,
"@" USEC_FMT " → %s → @" USEC_FMT " → %s%s",
x, xx, y, yy,
@@ -409,7 +410,7 @@ static void test_format_timestamp_impl(usec_t x) {
}
static void test_format_timestamp_loop(void) {
- test_format_timestamp_impl(USEC_PER_SEC);
+ test_format_timestamp_impl(USEC_PER_DAY + USEC_PER_SEC);
/* Two cases which trigger https://github.com/systemd/systemd/issues/28472 */
test_format_timestamp_impl(1504938962980066);

View File

@ -0,0 +1,61 @@
From cb442eb90085aae9db3bdf0cd7a4730912dba3ef Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Sat, 14 Dec 2024 16:49:54 +0900
Subject: [PATCH] test-time-util: fix truncation of usec to sec
Also
- use ASSERT_XYZ() macros,
- log tzname[] on failure.
(cherry picked from commit 3f1d499964abb6a4c0141d7ea8f852829880adff)
Related: RHEL-109488
---
src/test/test-time-util.c | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c
index 45d7541415..a5443ad7d7 100644
--- a/src/test/test-time-util.c
+++ b/src/test/test-time-util.c
@@ -384,28 +384,32 @@ TEST(format_timestamp) {
static void test_format_timestamp_impl(usec_t x) {
bool success, override;
const char *xx, *yy;
- usec_t y;
+ usec_t y, x_sec, y_sec;
xx = FORMAT_TIMESTAMP(x);
- assert_se(xx);
- assert_se(parse_timestamp(xx, &y) >= 0);
+ ASSERT_NOT_NULL(xx);
+ ASSERT_OK(parse_timestamp(xx, &y));
yy = FORMAT_TIMESTAMP(y);
- assert_se(yy);
+ ASSERT_NOT_NULL(yy);
- success = (x / USEC_PER_SEC == y / USEC_PER_SEC) && streq(xx, yy);
+ x_sec = x / USEC_PER_SEC;
+ y_sec = y / USEC_PER_SEC;
+ success = (x_sec == y_sec) && streq(xx, yy);
/* Workaround for https://github.com/systemd/systemd/issues/28472
* and https://github.com/systemd/systemd/pull/35471. */
override = !success &&
(STRPTR_IN_SET(tzname[0], "CAT", "EAT", "WET") ||
STRPTR_IN_SET(tzname[1], "CAT", "EAT", "WET")) &&
- DIV_ROUND_UP(x > y ? x - y : y - x, USEC_PER_SEC) == 3600; /* 1 hour, ignore fractional second */
+ (x_sec > y_sec ? x_sec - y_sec : y_sec - x_sec) == 3600; /* 1 hour, ignore fractional second */
log_full(success ? LOG_DEBUG : override ? LOG_WARNING : LOG_ERR,
"@" USEC_FMT " → %s → @" USEC_FMT " → %s%s",
x, xx, y, yy,
override ? ", ignoring." : "");
if (!override) {
- assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
- assert_se(streq(xx, yy));
+ if (!success)
+ log_warning("tzname[0]=\"%s\", tzname[1]=\"%s\"", tzname[0], tzname[1]);
+ ASSERT_EQ(x_sec, y_sec);
+ ASSERT_STREQ(xx, yy);
}
}

View File

@ -0,0 +1,63 @@
From e0ac4a4632c99750ad63476c3ae62a1988b2883b Mon Sep 17 00:00:00 2001
From: Luca Boccassi <bluca@debian.org>
Date: Fri, 26 Jan 2024 00:22:38 +0000
Subject: [PATCH] test: unset TZ before timezone-sensitive unit tests are run
Some tests have hard-coded results that need to match, and change if
the caller has a timezone set via the TZ= environment variable, as it
is the case during reproducible build tests. Unset it.
(cherry picked from commit 1e902c3463024bb328bf0d01a5d58a69e1ccf739)
Related: RHEL-109488
---
src/test/test-calendarspec.c | 9 ++++++++-
src/test/test-date.c | 3 +++
src/test/test-time-util.c | 3 +++
3 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c
index 564983b699..4699991535 100644
--- a/src/test/test-calendarspec.c
+++ b/src/test/test-calendarspec.c
@@ -260,4 +260,11 @@ TEST(calendar_spec_from_string) {
assert_se(calendar_spec_from_string("*:4,30:*\n", &c) == -EINVAL);
}
-DEFINE_TEST_MAIN(LOG_INFO);
+static int intro(void) {
+ /* Tests have hard-coded results that do not expect a specific timezone to be set by the caller */
+ assert_se(unsetenv("TZ") >= 0);
+
+ return EXIT_SUCCESS;
+}
+
+DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);
diff --git a/src/test/test-date.c b/src/test/test-date.c
index 097066b61a..cc11bd999e 100644
--- a/src/test/test-date.c
+++ b/src/test/test-date.c
@@ -62,6 +62,9 @@ static void test_one_noutc(const char *p) {
}
int main(int argc, char *argv[]) {
+ /* Tests have hard-coded results that do not expect a specific timezone to be set by the caller */
+ assert_se(unsetenv("TZ") >= 0);
+
test_setup_logging(LOG_DEBUG);
test_one("17:41");
diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c
index a5443ad7d7..21b05a3010 100644
--- a/src/test/test-time-util.c
+++ b/src/test/test-time-util.c
@@ -1016,6 +1016,9 @@ TEST(timezone_offset_change) {
}
static int intro(void) {
+ /* Tests have hard-coded results that do not expect a specific timezone to be set by the caller */
+ assert_se(unsetenv("TZ") >= 0);
+
log_info("realtime=" USEC_FMT "\n"
"monotonic=" USEC_FMT "\n"
"boottime=" USEC_FMT "\n",

View File

@ -0,0 +1,30 @@
From bef180f6ddc06bc6e669024b5d1fb9b97a1e3f4d Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <fsumsal@redhat.com>
Date: Tue, 2 Sep 2025 17:33:35 +0200
Subject: [PATCH] meson: extend timeout for test-time-util
As it runs through many timezones and hits the default timeout when
running under sanitizers.
Based on upstream's b66b3c409900a77b3da7b366ae5a0179abacea99.
rhel-only: ci
Related: RHEL-109488
---
src/test/meson.build | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/test/meson.build b/src/test/meson.build
index 5547271ee7..9de487ced5 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -459,7 +459,8 @@ tests += [
[files('test-fileio.c')],
- [files('test-time-util.c')],
+ [files('test-time-util.c'),
+ [], [], [], '', 'timeout=120'],
[files('test-clock.c')],

View File

@ -0,0 +1,25 @@
From c5bdf8c148fc9ab18d3412756ada7317caece6fe Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 14 Feb 2023 01:40:56 +0900
Subject: [PATCH] time-util: use DEFINE_STRING_TABLE_LOOKUP_TO_STRING() macro
(cherry picked from commit d227a42aadf04c23c668ac3089bc7b4a9baaf7e1)
Related: RHEL-109488
---
src/basic/time-util.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index f5e10bba1a..6eee8a48a7 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -1616,7 +1616,7 @@ static const char* const timestamp_style_table[_TIMESTAMP_STYLE_MAX] = {
};
/* Use the macro for enum → string to allow for aliases */
-_DEFINE_STRING_TABLE_LOOKUP_TO_STRING(timestamp_style, TimestampStyle,);
+DEFINE_STRING_TABLE_LOOKUP_TO_STRING(timestamp_style, TimestampStyle);
/* For the string → enum mapping we use the generic implementation, but also support two aliases */
TimestampStyle timestamp_style_from_string(const char *s) {

View File

@ -0,0 +1,30 @@
From 243ecafd63c2c0f8cbdecee770626143bf4def62 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 14 Feb 2023 01:41:38 +0900
Subject: [PATCH] time-util: align string table
(cherry picked from commit e01a8fdd2645c06cdb9057bd5b8a45ab02c0d6ee)
Related: RHEL-109488
---
src/basic/time-util.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index 6eee8a48a7..404fde01db 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -1609,10 +1609,10 @@ int time_change_fd(void) {
static const char* const timestamp_style_table[_TIMESTAMP_STYLE_MAX] = {
[TIMESTAMP_PRETTY] = "pretty",
- [TIMESTAMP_US] = "us",
- [TIMESTAMP_UTC] = "utc",
+ [TIMESTAMP_US] = "us",
+ [TIMESTAMP_UTC] = "utc",
[TIMESTAMP_US_UTC] = "us+utc",
- [TIMESTAMP_UNIX] = "unix",
+ [TIMESTAMP_UNIX] = "unix",
};
/* Use the macro for enum → string to allow for aliases */

View File

@ -0,0 +1,316 @@
From 753dd2e5f28a9b5a552efda75bcbec20ad501e69 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 14 Feb 2023 02:04:31 +0900
Subject: [PATCH] time-util: rename variables
(cherry picked from commit cf98b66d1ad0ff0e9ee0444861069ebade038dbb)
Related: RHEL-109488
---
src/basic/time-util.c | 86 +++++++++++++++++++++----------------------
src/basic/time-util.h | 16 ++++----
2 files changed, 51 insertions(+), 51 deletions(-)
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index 404fde01db..7dbd3af20a 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -604,7 +604,7 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
return buf;
}
-static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
+static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
static const struct {
const char *name;
const int nr;
@@ -628,7 +628,7 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
const char *k, *utc = NULL, *tzn = NULL;
struct tm tm, copy;
time_t x;
- usec_t x_usec, plus = 0, minus = 0, ret;
+ usec_t usec, x_usec, plus = 0, minus = 0;
int r, weekday = -1, dst = -1;
size_t i;
@@ -651,9 +651,9 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
assert(t);
if (t[0] == '@' && !with_tz)
- return parse_sec(t + 1, usec);
+ return parse_sec(t + 1, ret);
- ret = now(CLOCK_REALTIME);
+ usec = now(CLOCK_REALTIME);
if (!with_tz) {
if (streq(t, "now"))
@@ -734,7 +734,7 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
}
}
- x = (time_t) (ret / USEC_PER_SEC);
+ x = (time_t) (usec / USEC_PER_SEC);
x_usec = 0;
if (!localtime_or_gmtime_r(&x, &tm, utc))
@@ -871,24 +871,24 @@ from_tm:
if (x < 0)
return -EINVAL;
- ret = (usec_t) x * USEC_PER_SEC + x_usec;
- if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX)
+ usec = (usec_t) x * USEC_PER_SEC + x_usec;
+ if (usec > USEC_TIMESTAMP_FORMATTABLE_MAX)
return -EINVAL;
finish:
- if (ret + plus < ret) /* overflow? */
+ if (usec + plus < usec) /* overflow? */
return -EINVAL;
- ret += plus;
- if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX)
+ usec += plus;
+ if (usec > USEC_TIMESTAMP_FORMATTABLE_MAX)
return -EINVAL;
- if (ret >= minus)
- ret -= minus;
+ if (usec >= minus)
+ usec -= minus;
else
return -EINVAL;
- if (usec)
- *usec = ret;
+ if (ret)
+ *ret = usec;
return 0;
}
@@ -897,7 +897,7 @@ typedef struct ParseTimestampResult {
int return_value;
} ParseTimestampResult;
-int parse_timestamp(const char *t, usec_t *usec) {
+int parse_timestamp(const char *t, usec_t *ret) {
char *last_space, *tz = NULL;
ParseTimestampResult *shared, tmp;
int r;
@@ -907,7 +907,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
tz = last_space + 1;
if (!tz || endswith_no_case(t, " UTC"))
- return parse_timestamp_impl(t, usec, false);
+ return parse_timestamp_impl(t, ret, false);
shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
if (shared == MAP_FAILED)
@@ -949,13 +949,13 @@ int parse_timestamp(const char *t, usec_t *usec) {
if (munmap(shared, sizeof *shared) != 0)
return negative_errno();
- if (tmp.return_value == 0 && usec)
- *usec = tmp.usec;
+ if (tmp.return_value == 0 && ret)
+ *ret = tmp.usec;
return tmp.return_value;
}
-static const char* extract_multiplier(const char *p, usec_t *multiplier) {
+static const char* extract_multiplier(const char *p, usec_t *ret) {
static const struct {
const char *suffix;
usec_t usec;
@@ -996,7 +996,7 @@ static const char* extract_multiplier(const char *p, usec_t *multiplier) {
e = startswith(p, table[i].suffix);
if (e) {
- *multiplier = table[i].usec;
+ *ret = table[i].usec;
return e;
}
}
@@ -1004,9 +1004,9 @@ static const char* extract_multiplier(const char *p, usec_t *multiplier) {
return p;
}
-int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
+int parse_time(const char *t, usec_t *ret, usec_t default_unit) {
const char *p, *s;
- usec_t r = 0;
+ usec_t usec = 0;
bool something = false;
assert(t);
@@ -1021,8 +1021,8 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
if (*s != 0)
return -EINVAL;
- if (usec)
- *usec = USEC_INFINITY;
+ if (ret)
+ *ret = USEC_INFINITY;
return 0;
}
@@ -1069,10 +1069,10 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
return -ERANGE;
k = (usec_t) l * multiplier;
- if (k >= USEC_INFINITY - r)
+ if (k >= USEC_INFINITY - usec)
return -ERANGE;
- r += k;
+ usec += k;
something = true;
@@ -1082,10 +1082,10 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
k = (usec_t) (*b - '0') * m;
- if (k >= USEC_INFINITY - r)
+ if (k >= USEC_INFINITY - usec)
return -ERANGE;
- r += k;
+ usec += k;
}
/* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge" */
@@ -1094,13 +1094,13 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
}
}
- if (usec)
- *usec = r;
+ if (ret)
+ *ret = usec;
return 0;
}
-int parse_sec(const char *t, usec_t *usec) {
- return parse_time(t, usec, USEC_PER_SEC);
+int parse_sec(const char *t, usec_t *ret) {
+ return parse_time(t, ret, USEC_PER_SEC);
}
int parse_sec_fix_0(const char *t, usec_t *ret) {
@@ -1127,7 +1127,7 @@ int parse_sec_def_infinity(const char *t, usec_t *ret) {
return parse_sec(t, ret);
}
-static const char* extract_nsec_multiplier(const char *p, nsec_t *multiplier) {
+static const char* extract_nsec_multiplier(const char *p, nsec_t *ret) {
static const struct {
const char *suffix;
nsec_t nsec;
@@ -1172,7 +1172,7 @@ static const char* extract_nsec_multiplier(const char *p, nsec_t *multiplier) {
e = startswith(p, table[i].suffix);
if (e) {
- *multiplier = table[i].nsec;
+ *ret = table[i].nsec;
return e;
}
}
@@ -1180,13 +1180,13 @@ static const char* extract_nsec_multiplier(const char *p, nsec_t *multiplier) {
return p;
}
-int parse_nsec(const char *t, nsec_t *nsec) {
+int parse_nsec(const char *t, nsec_t *ret) {
const char *p, *s;
- nsec_t r = 0;
+ nsec_t nsec = 0;
bool something = false;
assert(t);
- assert(nsec);
+ assert(ret);
p = t;
@@ -1197,7 +1197,7 @@ int parse_nsec(const char *t, nsec_t *nsec) {
if (*s != 0)
return -EINVAL;
- *nsec = NSEC_INFINITY;
+ *ret = NSEC_INFINITY;
return 0;
}
@@ -1244,10 +1244,10 @@ int parse_nsec(const char *t, nsec_t *nsec) {
return -ERANGE;
k = (nsec_t) l * multiplier;
- if (k >= NSEC_INFINITY - r)
+ if (k >= NSEC_INFINITY - nsec)
return -ERANGE;
- r += k;
+ nsec += k;
something = true;
@@ -1257,10 +1257,10 @@ int parse_nsec(const char *t, nsec_t *nsec) {
for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
k = (nsec_t) (*b - '0') * m;
- if (k >= NSEC_INFINITY - r)
+ if (k >= NSEC_INFINITY - nsec)
return -ERANGE;
- r += k;
+ nsec += k;
}
/* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge" */
@@ -1269,7 +1269,7 @@ int parse_nsec(const char *t, nsec_t *nsec) {
}
}
- *nsec = r;
+ *ret = nsec;
return 0;
}
diff --git a/src/basic/time-util.h b/src/basic/time-util.h
index c98f95a530..9d44cac747 100644
--- a/src/basic/time-util.h
+++ b/src/basic/time-util.h
@@ -141,15 +141,15 @@ static inline char* format_timestamp(char *buf, size_t l, usec_t t) {
#define FORMAT_TIMESTAMP_STYLE(t, style) \
format_timestamp_style((char[FORMAT_TIMESTAMP_MAX]){}, FORMAT_TIMESTAMP_MAX, t, style)
-int parse_timestamp(const char *t, usec_t *usec);
+int parse_timestamp(const char *t, usec_t *ret);
-int parse_sec(const char *t, usec_t *usec);
-int parse_sec_fix_0(const char *t, usec_t *usec);
-int parse_sec_def_infinity(const char *t, usec_t *usec);
-int parse_time(const char *t, usec_t *usec, usec_t default_unit);
-int parse_nsec(const char *t, nsec_t *nsec);
+int parse_sec(const char *t, usec_t *ret);
+int parse_sec_fix_0(const char *t, usec_t *ret);
+int parse_sec_def_infinity(const char *t, usec_t *ret);
+int parse_time(const char *t, usec_t *ret, usec_t default_unit);
+int parse_nsec(const char *t, nsec_t *ret);
-int get_timezones(char ***l);
+int get_timezones(char ***ret);
int verify_timezone(const char *name, int log_level);
static inline bool timezone_is_valid(const char *name, int log_level) {
return verify_timezone(name, log_level) >= 0;
@@ -159,7 +159,7 @@ bool clock_supported(clockid_t clock);
usec_t usec_shift_clock(usec_t, clockid_t from, clockid_t to);
-int get_timezone(char **timezone);
+int get_timezone(char **ret);
time_t mktime_or_timegm(struct tm *tm, bool utc);
struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc);

View File

@ -0,0 +1,115 @@
From 23f6608ffa05ce80ebfbca9a28369ff858e9d42e Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 14 Feb 2023 02:06:13 +0900
Subject: [PATCH] time-util: add assertions
(cherry picked from commit dff3bddc5416834d42cc682cb544732a4b91db3b)
Related: RHEL-109488
---
src/basic/time-util.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index 7dbd3af20a..ac28dc9be6 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -172,6 +172,8 @@ dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
dual_timestamp* dual_timestamp_from_boottime(dual_timestamp *ts, usec_t u) {
usec_t nowm;
+ assert(ts);
+
if (u == USEC_INFINITY) {
ts->realtime = ts->monotonic = USEC_INFINITY;
return ts;
@@ -184,6 +186,7 @@ dual_timestamp* dual_timestamp_from_boottime(dual_timestamp *ts, usec_t u) {
}
usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock) {
+ assert(ts);
switch (clock) {
@@ -421,6 +424,8 @@ char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
const char *s;
usec_t n, d;
+ assert(buf);
+
if (!timestamp_is_set(t))
return NULL;
@@ -902,6 +907,8 @@ int parse_timestamp(const char *t, usec_t *ret) {
ParseTimestampResult *shared, tmp;
int r;
+ assert(t);
+
last_space = strrchr(t, ' ');
if (last_space != NULL && timezone_is_valid(last_space + 1, LOG_DEBUG))
tz = last_space + 1;
@@ -991,6 +998,9 @@ static const char* extract_multiplier(const char *p, usec_t *ret) {
{ "µs", 1ULL },
};
+ assert(p);
+ assert(ret);
+
for (size_t i = 0; i < ELEMENTSOF(table); i++) {
char *e;
@@ -1119,6 +1129,9 @@ int parse_sec_fix_0(const char *t, usec_t *ret) {
}
int parse_sec_def_infinity(const char *t, usec_t *ret) {
+ assert(t);
+ assert(ret);
+
t += strspn(t, WHITESPACE);
if (isempty(t)) {
*ret = USEC_INFINITY;
@@ -1167,6 +1180,9 @@ static const char* extract_nsec_multiplier(const char *p, nsec_t *ret) {
};
size_t i;
+ assert(p);
+ assert(ret);
+
for (i = 0; i < ELEMENTSOF(table); i++) {
char *e;
@@ -1320,6 +1336,8 @@ static int get_timezones_from_tzdata_zi(char ***ret) {
_cleanup_strv_free_ char **zones = NULL;
int r;
+ assert(ret);
+
f = fopen("/usr/share/zoneinfo/tzdata.zi", "re");
if (!f)
return -errno;
@@ -1477,6 +1495,8 @@ int get_timezone(char **ret) {
char *z;
int r;
+ assert(ret);
+
r = readlink_malloc("/etc/localtime", &t);
if (r == -ENOENT) {
/* If the symlink does not exist, assume "UTC", like glibc does */
@@ -1506,10 +1526,15 @@ int get_timezone(char **ret) {
}
time_t mktime_or_timegm(struct tm *tm, bool utc) {
+ assert(tm);
+
return utc ? timegm(tm) : mktime(tm);
}
struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
+ assert(t);
+ assert(tm);
+
return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
}

View File

@ -0,0 +1,54 @@
From a3c08667c9abaf60793ed35e93123bc5f89981f3 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 14 Feb 2023 03:43:58 +0900
Subject: [PATCH] time-util: drop redundant else
(cherry picked from commit 17d1ebfc43c3b971d20ff2806acc634ee153eef6)
Related: RHEL-109488
---
src/basic/time-util.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index ac28dc9be6..c5b91fde66 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -664,21 +664,23 @@ static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
if (streq(t, "now"))
goto finish;
- else if (t[0] == '+') {
+ if (t[0] == '+') {
r = parse_sec(t+1, &plus);
if (r < 0)
return r;
goto finish;
+ }
- } else if (t[0] == '-') {
+ if (t[0] == '-') {
r = parse_sec(t+1, &minus);
if (r < 0)
return r;
goto finish;
+ }
- } else if ((k = endswith(t, " ago"))) {
+ if ((k = endswith(t, " ago"))) {
t = strndupa_safe(t, k - t);
r = parse_sec(t, &minus);
@@ -686,8 +688,9 @@ static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
return r;
goto finish;
+ }
- } else if ((k = endswith(t, " left"))) {
+ if ((k = endswith(t, " left"))) {
t = strndupa_safe(t, k - t);
r = parse_sec(t, &plus);

View File

@ -0,0 +1,50 @@
From 50a7d58a24a381e265436c14303e7bb368a4b147 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 14 Feb 2023 03:41:26 +0900
Subject: [PATCH] time-util: do not use strdupa()
The input string may come from command line, config files.
(cherry picked from commit 804537bdc420bb82e54b455b7a10d542c8f029dd)
Related: RHEL-109488
---
src/basic/time-util.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index c5b91fde66..64cdcea594 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -681,9 +681,13 @@ static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
}
if ((k = endswith(t, " ago"))) {
- t = strndupa_safe(t, k - t);
+ _cleanup_free_ char *buf = NULL;
- r = parse_sec(t, &minus);
+ buf = strndup(t, k - t);
+ if (!buf)
+ return -ENOMEM;
+
+ r = parse_sec(buf, &minus);
if (r < 0)
return r;
@@ -691,9 +695,13 @@ static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
}
if ((k = endswith(t, " left"))) {
- t = strndupa_safe(t, k - t);
+ _cleanup_free_ char *buf = NULL;
+
+ buf = strndup(t, k - t);
+ if (!buf)
+ return -ENOMEM;
- r = parse_sec(t, &plus);
+ r = parse_sec(buf, &plus);
if (r < 0)
return r;

View File

@ -0,0 +1,49 @@
From eabf4db441c885a78d5726838004bbb9436dbf91 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 14 Feb 2023 04:14:24 +0900
Subject: [PATCH] time-util: use result from startswith_no_case()
No functional change, just refactoring.
(cherry picked from commit f2ecfd8bc1e6d09173e9f98c5ac1b19b755a3c25)
Related: RHEL-109488
---
src/basic/time-util.c | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index 64cdcea594..047dad0fec 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -635,7 +635,6 @@ static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
time_t x;
usec_t usec, x_usec, plus = 0, minus = 0;
int r, weekday = -1, dst = -1;
- size_t i;
/* Allowed syntaxes:
*
@@ -775,18 +774,13 @@ static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
goto from_tm;
}
- for (i = 0; i < ELEMENTSOF(day_nr); i++) {
- size_t skip;
-
- if (!startswith_no_case(t, day_nr[i].name))
- continue;
-
- skip = strlen(day_nr[i].name);
- if (t[skip] != ' ')
+ for (size_t i = 0; i < ELEMENTSOF(day_nr); i++) {
+ k = startswith_no_case(t, day_nr[i].name);
+ if (!k || *k != ' ')
continue;
weekday = day_nr[i].nr;
- t += skip + 1;
+ t = k + 1;
break;
}

View File

@ -0,0 +1,47 @@
From 9f7d490b1c16f0444987dab7ce70287b59d98cf9 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 14 Feb 2023 04:27:27 +0900
Subject: [PATCH] time-util: use usec_add() and usec_sub_unsigned()
And move the check with USEC_TIMESTAMP_FORMATTABLE_MAX at the end,
as usec_add() can handle overflow correctly.
(cherry picked from commit db43717e982e1361eee4bdcd92167d6c47eb627c)
Related: RHEL-109488
---
src/basic/time-util.c | 17 +++++++----------
1 file changed, 7 insertions(+), 10 deletions(-)
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index 047dad0fec..ba5e17bd9d 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -881,20 +881,17 @@ from_tm:
if (x < 0)
return -EINVAL;
- usec = (usec_t) x * USEC_PER_SEC + x_usec;
- if (usec > USEC_TIMESTAMP_FORMATTABLE_MAX)
- return -EINVAL;
+ usec = usec_add(x * USEC_PER_SEC, x_usec);
finish:
- if (usec + plus < usec) /* overflow? */
- return -EINVAL;
- usec += plus;
- if (usec > USEC_TIMESTAMP_FORMATTABLE_MAX)
+ usec = usec_add(usec, plus);
+
+ if (usec < minus)
return -EINVAL;
- if (usec >= minus)
- usec -= minus;
- else
+ usec = usec_sub_unsigned(usec, minus);
+
+ if (usec > USEC_TIMESTAMP_FORMATTABLE_MAX)
return -EINVAL;
if (ret)

View File

@ -0,0 +1,72 @@
From 2dafd8e6be624f93c757ca9c739d502ed73d79c0 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 14 Feb 2023 04:27:52 +0900
Subject: [PATCH] time-util: shorten code a bit
No functional change, just refactoring.
(cherry picked from commit 1d2c42c5dc765c57b4fba6b7c629093aa20685a8)
Related: RHEL-109488
---
src/basic/time-util.c | 25 +++++++++----------------
1 file changed, 9 insertions(+), 16 deletions(-)
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index ba5e17bd9d..6e1b34b025 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -633,8 +633,9 @@ static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
const char *k, *utc = NULL, *tzn = NULL;
struct tm tm, copy;
time_t x;
- usec_t usec, x_usec, plus = 0, minus = 0;
+ usec_t usec, plus = 0, minus = 0;
int r, weekday = -1, dst = -1;
+ unsigned fractional = 0;
/* Allowed syntaxes:
*
@@ -750,7 +751,6 @@ static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
}
x = (time_t) (usec / USEC_PER_SEC);
- x_usec = 0;
if (!localtime_or_gmtime_r(&x, &tm, utc))
return -EINVAL;
@@ -859,19 +859,12 @@ static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
return -EINVAL;
parse_usec:
- {
- unsigned add;
-
- k++;
- r = parse_fractional_part_u(&k, 6, &add);
- if (r < 0)
- return -EINVAL;
-
- if (*k)
- return -EINVAL;
-
- x_usec = add;
- }
+ k++;
+ r = parse_fractional_part_u(&k, 6, &fractional);
+ if (r < 0)
+ return -EINVAL;
+ if (*k != '\0')
+ return -EINVAL;
from_tm:
if (weekday >= 0 && tm.tm_wday != weekday)
@@ -881,7 +874,7 @@ from_tm:
if (x < 0)
return -EINVAL;
- usec = usec_add(x * USEC_PER_SEC, x_usec);
+ usec = usec_add(x * USEC_PER_SEC, fractional);
finish:
usec = usec_add(usec, plus);

View File

@ -0,0 +1,69 @@
From 5bfcf206bd16079ae8030a2c912ee8377a3f6d5f Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 15 Feb 2023 13:46:50 +0900
Subject: [PATCH] time-util: rename variables
No functional changes, just refactoring.
(cherry picked from commit a83c1baaeb510f1916d2d8cf0324d100708c7073)
Related: RHEL-109488
---
src/basic/time-util.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index 6e1b34b025..d468848d09 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -632,10 +632,10 @@ static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
const char *k, *utc = NULL, *tzn = NULL;
struct tm tm, copy;
- time_t x;
usec_t usec, plus = 0, minus = 0;
- int r, weekday = -1, dst = -1;
+ int r, weekday = -1, isdst = -1;
unsigned fractional = 0;
+ time_t sec;
/* Allowed syntaxes:
*
@@ -744,18 +744,18 @@ static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
if (IN_SET(j, 0, 1)) {
/* Found one of the two timezones specified. */
t = strndupa_safe(t, e - t - 1);
- dst = j;
+ isdst = j;
tzn = tzname[j];
}
}
}
- x = (time_t) (usec / USEC_PER_SEC);
+ sec = (time_t) (usec / USEC_PER_SEC);
- if (!localtime_or_gmtime_r(&x, &tm, utc))
+ if (!localtime_or_gmtime_r(&sec, &tm, utc))
return -EINVAL;
- tm.tm_isdst = dst;
+ tm.tm_isdst = isdst;
if (!with_tz && tzn)
tm.tm_zone = tzn;
@@ -870,11 +870,11 @@ from_tm:
if (weekday >= 0 && tm.tm_wday != weekday)
return -EINVAL;
- x = mktime_or_timegm(&tm, utc);
- if (x < 0)
+ sec = mktime_or_timegm(&tm, utc);
+ if (sec < 0)
return -EINVAL;
- usec = usec_add(x * USEC_PER_SEC, fractional);
+ usec = usec_add(sec * USEC_PER_SEC, fractional);
finish:
usec = usec_add(usec, plus);

View File

@ -0,0 +1,44 @@
From a1a7ab09cf96e30cfd0c89efaf8d03a5dc81e928 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 15 Feb 2023 13:51:15 +0900
Subject: [PATCH] time-util: drop unnecessary assignment of timezone name
As mktime() does not use timezone neme.
(cherry picked from commit 97c5f7ba1f50fcd7b982b995b46692c8cad4afaa)
Related: RHEL-109488
---
src/basic/time-util.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index d468848d09..92928e88a4 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -630,7 +630,7 @@ static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
{ "Sat", 6 },
};
- const char *k, *utc = NULL, *tzn = NULL;
+ const char *k, *utc = NULL;
struct tm tm, copy;
usec_t usec, plus = 0, minus = 0;
int r, weekday = -1, isdst = -1;
@@ -745,7 +745,6 @@ static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
/* Found one of the two timezones specified. */
t = strndupa_safe(t, e - t - 1);
isdst = j;
- tzn = tzname[j];
}
}
}
@@ -756,8 +755,6 @@ static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
return -EINVAL;
tm.tm_isdst = isdst;
- if (!with_tz && tzn)
- tm.tm_zone = tzn;
if (streq(t, "today")) {
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;

View File

@ -0,0 +1,275 @@
From e4b1932cd1c0ad2d42a6271cb651e6979b5962ed Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 14 Feb 2023 03:39:15 +0900
Subject: [PATCH] time-util: make parse_timestamp() use the RFC-822/ISO 8601
standard timezone spec
If the timezone is specified with a number e.g. +0900 or so, then
let's parse the time as a UTC, and adjust it with the specified time
shift.
Otherwise, if an area has timezone change, e.g.
---
Africa/Casablanca Sun Jun 17 01:59:59 2018 UT = Sun Jun 17 01:59:59 2018 +00 isdst=0 gmtoff=0
Africa/Casablanca Sun Jun 17 02:00:00 2018 UT = Sun Jun 17 03:00:00 2018 +01 isdst=1 gmtoff=3600
Africa/Casablanca Sun Oct 28 01:59:59 2018 UT = Sun Oct 28 02:59:59 2018 +01 isdst=1 gmtoff=3600
Africa/Casablanca Sun Oct 28 02:00:00 2018 UT = Sun Oct 28 03:00:00 2018 +01 isdst=0 gmtoff=3600
---
then we could not determine isdst from the timezone (+01 in the above)
and mktime() will provide wrong results.
Fixes #26370.
(cherry picked from commit 7a9afae6040af0417d893328cb44b622dcdcb94f)
Related: RHEL-109488
---
src/basic/time-util.c | 174 +++++++++++++++++++++++++++---------------
1 file changed, 112 insertions(+), 62 deletions(-)
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index 92928e88a4..6fbbc2f655 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -609,7 +609,14 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
return buf;
}
-static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
+static int parse_timestamp_impl(
+ const char *t,
+ bool with_tz,
+ bool utc,
+ int isdst,
+ long gmtoff,
+ usec_t *ret) {
+
static const struct {
const char *name;
const int nr;
@@ -630,11 +637,11 @@ static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
{ "Sat", 6 },
};
- const char *k, *utc = NULL;
- struct tm tm, copy;
usec_t usec, plus = 0, minus = 0;
- int r, weekday = -1, isdst = -1;
+ int r, weekday = -1;
unsigned fractional = 0;
+ const char *k;
+ struct tm tm, copy;
time_t sec;
/* Allowed syntaxes:
@@ -707,46 +714,6 @@ static int parse_timestamp_impl(const char *t, usec_t *ret, bool with_tz) {
goto finish;
}
-
- /* See if the timestamp is suffixed with UTC */
- utc = endswith_no_case(t, " UTC");
- if (utc)
- t = strndupa_safe(t, utc - t);
- else {
- const char *e = NULL;
- int j;
-
- tzset();
-
- /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note
- * that we only support the local timezones here, nothing else. Not because we
- * wouldn't want to, but simply because there are no nice APIs available to cover
- * this. By accepting the local time zone strings, we make sure that all timestamps
- * written by format_timestamp() can be parsed correctly, even though we don't
- * support arbitrary timezone specifications. */
-
- for (j = 0; j <= 1; j++) {
-
- if (isempty(tzname[j]))
- continue;
-
- e = endswith_no_case(t, tzname[j]);
- if (!e)
- continue;
- if (e == t)
- continue;
- if (e[-1] != ' ')
- continue;
-
- break;
- }
-
- if (IN_SET(j, 0, 1)) {
- /* Found one of the two timezones specified. */
- t = strndupa_safe(t, e - t - 1);
- isdst = j;
- }
- }
}
sec = (time_t) (usec / USEC_PER_SEC);
@@ -864,9 +831,32 @@ parse_usec:
return -EINVAL;
from_tm:
+ assert(plus == 0);
+ assert(minus == 0);
+
if (weekday >= 0 && tm.tm_wday != weekday)
return -EINVAL;
+ if (gmtoff < 0) {
+ plus = -gmtoff * USEC_PER_SEC;
+
+ /* If gmtoff is negative, the string maye be too old to be parsed as UTC.
+ * E.g. 1969-12-31 23:00:00 -06 == 1970-01-01 05:00:00 UTC
+ * We assumed that gmtoff is in the range of -24:00…+24:00, hence the only date we need to
+ * handle here is 1969-12-31. So, let's shift the date with one day, then subtract the shift
+ * later. */
+ if (tm.tm_year == 69 && tm.tm_mon == 11 && tm.tm_mday == 31) {
+ /* Thu 1970-01-01-00:00:00 */
+ tm.tm_year = 70;
+ tm.tm_mon = 0;
+ tm.tm_mday = 1;
+ tm.tm_wday = 4;
+ tm.tm_yday = 0;
+ minus = USEC_PER_DAY;
+ }
+ } else
+ minus = gmtoff * USEC_PER_SEC;
+
sec = mktime_or_timegm(&tm, utc);
if (sec < 0)
return -EINVAL;
@@ -889,24 +879,93 @@ finish:
return 0;
}
+static int parse_timestamp_with_tz(const char *t, size_t len, bool utc, int isdst, long gmtoff, usec_t *ret) {
+ _cleanup_free_ char *buf = NULL;
+
+ assert(t);
+ assert(len > 0);
+
+ buf = strndup(t, len);
+ if (!buf)
+ return -ENOMEM;
+
+ return parse_timestamp_impl(buf, /* with_tz = */ true, utc, isdst, gmtoff, ret);
+}
+
+static int parse_timestamp_maybe_with_tz(const char *t, size_t len, bool valid_tz, usec_t *ret) {
+ assert(t);
+ assert(len > 0);
+
+ tzset();
+
+ for (int j = 0; j <= 1; j++) {
+ if (isempty(tzname[j]))
+ continue;
+
+ if (!streq(t + len + 1, tzname[j]))
+ continue;
+
+ /* The specified timezone matches tzname[] of the local timezone. */
+ return parse_timestamp_with_tz(t, len, /* utc = */ false, /* isdst = */ j, /* gmtoff = */ 0, ret);
+ }
+
+ if (valid_tz)
+ /* We know that the specified timezone is a valid zoneinfo (e.g. Asia/Tokyo). So, simply drop
+ * the timezone and parse the remaining string as a local time. */
+ return parse_timestamp_with_tz(t, len, /* utc = */ false, /* isdst = */ -1, /* gmtoff = */ 0, ret);
+
+ return parse_timestamp_impl(t, /* with_tz = */ false, /* utc = */ false, /* isdst = */ -1, /* gmtoff = */ 0, ret);
+}
+
typedef struct ParseTimestampResult {
usec_t usec;
int return_value;
} ParseTimestampResult;
int parse_timestamp(const char *t, usec_t *ret) {
- char *last_space, *tz = NULL;
ParseTimestampResult *shared, tmp;
+ const char *k, *tz, *space;
+ struct tm tm;
int r;
assert(t);
- last_space = strrchr(t, ' ');
- if (last_space != NULL && timezone_is_valid(last_space + 1, LOG_DEBUG))
- tz = last_space + 1;
+ space = strrchr(t, ' ');
+ if (!space)
+ return parse_timestamp_impl(t, /* with_tz = */ false, /* utc = */ false, /* isdst = */ -1, /* gmtoff = */ 0, ret);
- if (!tz || endswith_no_case(t, " UTC"))
- return parse_timestamp_impl(t, ret, false);
+ /* The string starts with space. */
+ if (space == t)
+ return -EINVAL;
+
+ /* Shortcut, parse the string as UTC. */
+ if (streq(space + 1, "UTC"))
+ return parse_timestamp_with_tz(t, space - t, /* utc = */ true, /* isdst = */ -1, /* gmtoff = */ 0, ret);
+
+ /* If the timezone is compatible with RFC-822/ISO 8601 (e.g. +06, or -03:00) then parse the string as
+ * UTC and shift the result. */
+ k = strptime(space + 1, "%z", &tm);
+ if (k && *k == '\0') {
+ /* glibc accepts gmtoff more than 24 hours, but we refuse it. */
+ if ((usec_t) labs(tm.tm_gmtoff) > USEC_PER_DAY / USEC_PER_SEC)
+ return -EINVAL;
+
+ return parse_timestamp_with_tz(t, space - t, /* utc = */ true, /* isdst = */ -1, /* gmtoff = */ tm.tm_gmtoff, ret);
+ }
+
+ /* If the last word is not a timezone file (e.g. Asia/Tokyo), then let's check if it matches
+ * tzname[] of the local timezone, e.g. JST or CEST. */
+ if (!timezone_is_valid(space + 1, LOG_DEBUG))
+ return parse_timestamp_maybe_with_tz(t, space - t, /* valid_tz = */ false, ret);
+
+ /* Shortcut. If the current $TZ is equivalent to the specified timezone, it is not necessary to fork
+ * the process. */
+ tz = getenv("TZ");
+ if (tz && *tz == ':' && streq(tz + 1, space + 1))
+ return parse_timestamp_maybe_with_tz(t, space - t, /* valid_tz = */ true, ret);
+
+ /* Otherwise, to avoid polluting the current environment variables, let's fork the process and set
+ * the specified timezone in the child process. */
shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
if (shared == MAP_FAILED)
@@ -918,11 +977,10 @@ int parse_timestamp(const char *t, usec_t *ret) {
return r;
}
if (r == 0) {
- bool with_tz = true;
- char *colon_tz;
+ const char *colon_tz;
/* tzset(3) says $TZ should be prefixed with ":" if we reference timezone files */
- colon_tz = strjoina(":", tz);
+ colon_tz = strjoina(":", space + 1);
if (setenv("TZ", colon_tz, 1) != 0) {
shared->return_value = negative_errno();
@@ -931,15 +989,7 @@ int parse_timestamp(const char *t, usec_t *ret) {
tzset();
- /* If there is a timezone that matches the tzname fields, leave the parsing to the implementation.
- * Otherwise just cut it off. */
- with_tz = !STR_IN_SET(tz, tzname[0], tzname[1]);
-
- /* Cut off the timezone if we don't need it. */
- if (with_tz)
- t = strndupa_safe(t, last_space - t);
-
- shared->return_value = parse_timestamp_impl(t, &shared->usec, with_tz);
+ shared->return_value = parse_timestamp_maybe_with_tz(t, space - t, /* valid_tz = */ true, &shared->usec);
_exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,27 @@
From 008aed2736dac288700f1c177690904da9c5137d Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 3 Mar 2023 15:24:23 +0900
Subject: [PATCH] time-util: fix typo
Follow-up for 7a9afae6040af0417d893328cb44b622dcdcb94f.
(cherry picked from commit ca9c9d8d8e999fd80fc43d002c8d5b20c4c1a0a4)
Related: RHEL-109488
---
src/basic/time-util.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index 6fbbc2f655..66bf4c17bb 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -840,7 +840,7 @@ from_tm:
if (gmtoff < 0) {
plus = -gmtoff * USEC_PER_SEC;
- /* If gmtoff is negative, the string maye be too old to be parsed as UTC.
+ /* If gmtoff is negative, the string may be too old to be parsed as UTC.
* E.g. 1969-12-31 23:00:00 -06 == 1970-01-01 05:00:00 UTC
* We assumed that gmtoff is in the range of -24:00…+24:00, hence the only date we need to
* handle here is 1969-12-31. So, let's shift the date with one day, then subtract the shift

View File

@ -0,0 +1,36 @@
From 5e10617a3a450a2bb6fbe031d1861559192bc85c Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <fsumsal@redhat.com>
Date: Thu, 4 Sep 2025 15:31:27 +0200
Subject: [PATCH] ci: bump the tools tree to F42
To fix the failing SB key enrollment:
3h3hBdsDxe: loading Boot0001 "UEFI QEMU QEMU HARDDISK " from PciRoot(0x0)/Pci(0x4,0x0)/Scsi(0x1,0x0)
BdsDxe: starting Boot0001 "UEFI QEMU QEMU HARDDISK " from PciRoot(0x0)/Pci(0x4,0x0)/Scsi(0x1,0x0)
systemd-boot@0x7d189000,0x7d1a6000
Enrolling secure boot keys from directory: \loader\keys\auto
Failed to write PK secure boot variable: Security violation
systemd-stub@0x670fd000,0x67115000
Overlapping PE sections detected. Boot may fail due to image memory corruption!
EFI stub: Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path
EFI stub: Measured initrd data into PCR 9
rhel-only: ci
Related: RHEL-109488
---
.github/workflows/mkosi.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/mkosi.yml b/.github/workflows/mkosi.yml
index 808ae0148e..2694ba14ec 100644
--- a/.github/workflows/mkosi.yml
+++ b/.github/workflows/mkosi.yml
@@ -83,7 +83,7 @@ jobs:
[Host]
ToolsTree=default
ToolsTreeDistribution=fedora
- ToolsTreeRelease=41
+ ToolsTreeRelease=42
# Sometimes we run on a host with /dev/kvm, but it is broken, so explicitly disable it
QemuKvm=no
EOF

View File

@ -0,0 +1,27 @@
From 8cec69eb3fe332ac618c34780dd5275d931d9bf8 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Sun, 1 Dec 2024 14:46:40 +0900
Subject: [PATCH] journald: extend STDOUT_STREAMS_MAX to 64k
Closes #35390.
(cherry picked from commit c576ba7182f54f352c03f0768c9178b173fb8bcb)
Resolves: RHEL-111065
---
src/journal/journald-stream.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index 8bdcd8c2ae..3ec6e7fcf3 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -38,7 +38,7 @@
#include "unit-name.h"
#include "user-util.h"
-#define STDOUT_STREAMS_MAX 4096
+#define STDOUT_STREAMS_MAX (64*1024)
/* During the "setup" protocol phase of the stream logic let's define a different maximum line length than
* during the actual operational phase. We want to allow users to specify very short line lengths after all,

View File

@ -0,0 +1,163 @@
From fa27bab14e2ede08dcac41ab78901ab3b653e556 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Tue, 26 Aug 2025 15:30:49 +0200
Subject: [PATCH] Revert "Revert "udev-builtin-net_id: use firmware_node/sun
for ID_NET_NAME_SLOT""
This reverts commit ae92c09f0ddfea2ff6042e152eec9af86013da38.
Also introduce rhel-9.8 naming scheme.
rhel-only: policy
Resolves: RHEL-50103
---
man/systemd.net-naming-scheme.xml | 9 ++++-
src/shared/netif-naming-scheme.c | 1 +
src/shared/netif-naming-scheme.h | 2 +
src/udev/udev-builtin-net_id.c | 66 +++++++++++++++++++++++++++----
4 files changed, 70 insertions(+), 8 deletions(-)
diff --git a/man/systemd.net-naming-scheme.xml b/man/systemd.net-naming-scheme.xml
index 34e8e46459..c6ee7b4b6e 100644
--- a/man/systemd.net-naming-scheme.xml
+++ b/man/systemd.net-naming-scheme.xml
@@ -526,6 +526,13 @@
<listitem><para>Same as naming scheme <constant>rhel-9.5</constant>.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><constant>rhel-9.8</constant></term>
+
+ <listitem>
+ <para>PCI slot number is now read from <constant>firmware_node/sun</constant> sysfs file.</para></listitem>
+ </varlistentry>
+
</variablelist>
<para>By default <constant>rhel-9.0</constant> is used.</para>
@@ -679,7 +686,7 @@ ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
</example>
<example>
- <title>PCI Ethernet card in hotplug slot with firmware index number</title>
+ <title>PCI Ethernet card in slot with firmware index number</title>
<programlisting># /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
ID_NET_NAME_MAC=enx000000000466
diff --git a/src/shared/netif-naming-scheme.c b/src/shared/netif-naming-scheme.c
index a38c3f1e2f..4ed866491e 100644
--- a/src/shared/netif-naming-scheme.c
+++ b/src/shared/netif-naming-scheme.c
@@ -47,6 +47,7 @@ static const NamingScheme naming_schemes[] = {
{ "rhel-9.5", NAMING_RHEL_9_5 },
{ "rhel-9.6", NAMING_RHEL_9_6 },
{ "rhel-9.7", NAMING_RHEL_9_7 },
+ { "rhel-9.8", NAMING_RHEL_9_8 },
/* … add more schemes here, as the logic to name devices is updated … */
EXTRA_NET_NAMING_MAP
diff --git a/src/shared/netif-naming-scheme.h b/src/shared/netif-naming-scheme.h
index 3cba656707..c16476522a 100644
--- a/src/shared/netif-naming-scheme.h
+++ b/src/shared/netif-naming-scheme.h
@@ -42,6 +42,7 @@ typedef enum NamingSchemeFlags {
* This is disabled since rhel-9.5, as it seems not to work at least for some setups. See upstream issue #28929. */
NAMING_DEVICETREE_ALIASES = 1 << 15, /* Generate names from devicetree aliases */
NAMING_SR_IOV_R = 1 << 17, /* Use "r" suffix for SR-IOV VF representors */
+ NAMING_FIRMWARE_NODE_SUN = 1 << 18, /* Use firmware_node/sun to get PCI slot number */
/* And now the masks that combine the features above */
NAMING_V238 = 0,
@@ -76,6 +77,7 @@ typedef enum NamingSchemeFlags {
NAMING_RHEL_9_5 = NAMING_RHEL_9_4 & ~NAMING_BRIDGE_MULTIFUNCTION_SLOT,
NAMING_RHEL_9_6 = NAMING_RHEL_9_5,
NAMING_RHEL_9_7 = NAMING_RHEL_9_5,
+ NAMING_RHEL_9_8 = NAMING_RHEL_9_5 | NAMING_FIRMWARE_NODE_SUN,
EXTRA_NET_NAMING_SCHEMES
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index 16c9971876..291fb4ba36 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -442,6 +442,51 @@ static int pci_get_hotplug_slot(sd_device *dev, uint32_t *ret) {
return -ENOENT;
}
+static int get_device_firmware_node_sun(sd_device *dev, uint32_t *ret) {
+ const char *attr;
+ int r;
+
+ assert(dev);
+ assert(ret);
+
+ r = device_get_sysattr_value_filtered(dev, "firmware_node/sun", &attr);
+ if (r < 0)
+ return log_device_debug_errno(dev, r, "Failed to read firmware_node/sun, ignoring: %m");
+
+ r = safe_atou32(attr, ret);
+ if (r < 0)
+ return log_device_warning_errno(dev, r, "Failed to parse firmware_node/sun '%s', ignoring: %m", attr);
+
+ return 0;
+}
+
+static int pci_get_slot_from_firmware_node_sun(sd_device *dev, uint32_t *ret) {
+ int r;
+ sd_device *slot_dev;
+
+ assert(dev);
+ assert(ret);
+
+ /* Try getting the ACPI _SUN for the device */
+ if (get_device_firmware_node_sun(dev, ret) >= 0)
+ return 0;
+
+ r = sd_device_get_parent_with_subsystem_devtype(dev, "pci", NULL, &slot_dev);
+ if (r < 0)
+ return log_device_debug_errno(dev, r, "Failed to find pci parent, ignoring: %m");
+
+ if (is_pci_bridge(slot_dev) && is_pci_multifunction(dev) <= 0)
+ return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ESTALE),
+ "Not using slot information because the parent pcieport "
+ "is a bridge and the PCI device is not multifunction.");
+
+ /* Try getting the ACPI _SUN from the parent pcieport */
+ if (get_device_firmware_node_sun(slot_dev, ret) >= 0)
+ return 0;
+
+ return -ENOENT;
+}
+
static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
const char *sysname, *attr;
unsigned domain, bus, slot, func;
@@ -517,13 +562,20 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
domain, bus, slot, func, strempty(info->phys_port_name), dev_port,
special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), empty_to_na(names->pci_path));
- r = pci_get_hotplug_slot(names->pcidev, &hotplug_slot);
- if (r < 0)
- return r;
- if (r > 0)
- /* If the hotplug slot is found through the function ID, then drop the domain from the name.
- * See comments in parse_hotplug_slot_from_function_id(). */
- domain = 0;
+ if (naming_scheme_has(NAMING_FIRMWARE_NODE_SUN))
+ r = pci_get_slot_from_firmware_node_sun(names->pcidev, &hotplug_slot);
+ else
+ r = -1;
+ /* If we don't find a slot using firmware_node/sun, fallback to hotplug_slot */
+ if (r < 0) {
+ r = pci_get_hotplug_slot(names->pcidev, &hotplug_slot);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ /* If the hotplug slot is found through the function ID, then drop the domain from the name.
+ * See comments in parse_hotplug_slot_from_function_id(). */
+ domain = 0;
+ }
s = names->pci_slot;
l = sizeof(names->pci_slot);

View File

@ -0,0 +1,43 @@
From 743c0fbd5ea56f926b36d6bbfc2d609bacd4353e Mon Sep 17 00:00:00 2001
From: Etienne Champetier <e.champetier@ateme.com>
Date: Thu, 22 Aug 2024 16:30:56 -0400
Subject: [PATCH] udev-builtin-net_id: ignore firmware_node/sun == 0
Since ID_NET_NAME_SLOT was introduced we ignore slot == 0
https://github.com/systemd/systemd/blob/0035597a30d120f70df2dd7da3d6128fb8ba6051/src/udev/udev-builtin-net_id.c#L139
Qemu sets _SUN to PCI_SLOT() for all NICs, so _SUN is not unique.
https://gitlab.com/qemu-project/qemu/-/issues/2530
In my tests with libvirt I can only set 'slot="0x00"' in interface definition,
so all NICs end up with _SUN == 0, and this commit is enough to avoid the issue.
Fixes 0a4ecc54cb9f2d3418b970c51bfadb69c34ae9eb
(cherry picked from commit 448f9f81fd32f8658449101ada2eadd853f6b06b)
Resolves: RHEL-50103
---
src/udev/udev-builtin-net_id.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index 291fb4ba36..e1895a38c0 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -453,10 +453,14 @@ static int get_device_firmware_node_sun(sd_device *dev, uint32_t *ret) {
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to read firmware_node/sun, ignoring: %m");
- r = safe_atou32(attr, ret);
+ uint32_t sun;
+ r = safe_atou32(attr, &sun);
if (r < 0)
return log_device_warning_errno(dev, r, "Failed to parse firmware_node/sun '%s', ignoring: %m", attr);
+ if (sun == 0)
+ return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL), "firmware_node/sun == 0, ignoring: %m");
+ *ret = sun;
return 0;
}

View File

@ -0,0 +1,36 @@
From c14ed0d0bf700b9959359004d5eef50d4d2db951 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 10 Jan 2023 14:08:41 +0100
Subject: [PATCH] fundamental: fix compile check for explicit_bzero
Our HAVE_* variables are defined to 0 or 1, so '#if defined(HAVE_*)' is always true.
The variable is not defined when compiling for EFI though, so we need the
additional guard.
Fixup for 3f92dc2fd4070b213e6bc85263a9bef06ec9a486.
(I don't want to do something like add -DHAVE_EXPLICIT_BZERO=0 to the commandline
in src/efi/boot/meson.build, because this quite verbose. Our compilation commandlines
are very long already. Let's instead keep this localized in this one spot in the
source file.)x
(cherry picked from commit 5deb391c6e6d2b8fd7b94234efea49cd6bee0d76)
Resolves: RHEL-108568
---
src/fundamental/memory-util-fundamental.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/fundamental/memory-util-fundamental.h b/src/fundamental/memory-util-fundamental.h
index 8f50d8b8e1..e0ae33dc0d 100644
--- a/src/fundamental/memory-util-fundamental.h
+++ b/src/fundamental/memory-util-fundamental.h
@@ -11,7 +11,7 @@
#include "macro-fundamental.h"
-#if defined(HAVE_EXPLICIT_BZERO)
+#if !defined(SD_BOOT) && HAVE_EXPLICIT_BZERO
static inline void *explicit_bzero_safe(void *p, size_t l) {
if (p && l > 0)
explicit_bzero(p, l);

View File

@ -0,0 +1,74 @@
From 9906687d228f71768ddf115799ebb39272d1f655 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Sun, 12 Mar 2023 20:57:16 +0900
Subject: [PATCH] time-util: make USEC_TIMESTAMP_FORMATTABLE_MAX for 32bit
system off by one day
As the same reason why we take one day off for 64bit case.
This also makes both upper bounds always defined for testing.
(cherry picked from commit bd5770da76ee157d3b31323ed2d22f5d9082bb36)
Related: RHEL-109488
---
src/basic/time-util.h | 14 +++++++++-----
src/test/test-date.c | 4 ++--
src/test/test-time-util.c | 2 +-
3 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/src/basic/time-util.h b/src/basic/time-util.h
index 9d44cac747..7f8bda0948 100644
--- a/src/basic/time-util.h
+++ b/src/basic/time-util.h
@@ -200,13 +200,17 @@ static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) {
return usec_sub_unsigned(timestamp, (usec_t) delta);
}
+/* 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. */
+#define USEC_TIMESTAMP_FORMATTABLE_MAX_64BIT ((usec_t) 253402214399000000) /* Thu 9999-12-30 23:59:59 UTC */
+/* With a 32bit time_t we can't go beyond 2038...
+ * We parse timestamp with RFC-822/ISO 8601 (e.g. +06, or -03:00) as UTC, hence the upper bound must be off
+ * by USEC_PER_DAY. See parse_timestamp() for more details. */
+#define USEC_TIMESTAMP_FORMATTABLE_MAX_32BIT (((usec_t) INT32_MAX) * USEC_PER_SEC - USEC_PER_DAY)
#if SIZEOF_TIME_T == 8
- /* 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. */
-# define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 253402214399000000)
+# define USEC_TIMESTAMP_FORMATTABLE_MAX USEC_TIMESTAMP_FORMATTABLE_MAX_64BIT
#elif SIZEOF_TIME_T == 4
-/* With a 32bit time_t we can't go beyond 2038... */
-# define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 2147483647000000)
+# define USEC_TIMESTAMP_FORMATTABLE_MAX USEC_TIMESTAMP_FORMATTABLE_MAX_32BIT
#else
# error "Yuck, time_t is neither 4 nor 8 bytes wide?"
#endif
diff --git a/src/test/test-date.c b/src/test/test-date.c
index cc11bd999e..ef316eeca7 100644
--- a/src/test/test-date.c
+++ b/src/test/test-date.c
@@ -104,8 +104,8 @@ int main(int argc, char *argv[]) {
test_should_fail("9999-12-31 00:00:00 UTC");
test_should_fail("10000-01-01 00:00:00 UTC");
#elif SIZEOF_TIME_T == 4
- test_should_pass("2038-01-19 03:14:07 UTC");
- test_should_fail("2038-01-19 03:14:08 UTC");
+ test_should_pass("2038-01-18 03:14:07 UTC");
+ test_should_fail("2038-01-18 03:14:08 UTC");
#endif
return 0;
diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c
index 21b05a3010..71ef5906ba 100644
--- a/src/test/test-time-util.c
+++ b/src/test/test-time-util.c
@@ -550,7 +550,7 @@ TEST(format_timestamp_utc) {
test_format_timestamp_utc_one(USEC_TIMESTAMP_FORMATTABLE_MAX, "Thu 9999-12-30 23:59:59 UTC");
test_format_timestamp_utc_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, "--- XXXX-XX-XX XX:XX:XX");
#elif SIZEOF_TIME_T == 4
- test_format_timestamp_utc_one(USEC_TIMESTAMP_FORMATTABLE_MAX, "Tue 2038-01-19 03:14:07 UTC");
+ test_format_timestamp_utc_one(USEC_TIMESTAMP_FORMATTABLE_MAX, "Mon 2038-01-18 03:14:07 UTC");
test_format_timestamp_utc_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, "--- XXXX-XX-XX XX:XX:XX");
#endif

View File

@ -21,7 +21,7 @@
Name: systemd Name: systemd
Url: https://systemd.io Url: https://systemd.io
Version: 252 Version: 252
Release: 55%{?dist} Release: 57%{?dist}
# For a breakdown of the licensing, see README # For a breakdown of the licensing, see README
License: LGPLv2+ and MIT and GPLv2+ License: LGPLv2+ and MIT and GPLv2+
Summary: System and Service Manager Summary: System and Service Manager
@ -1292,6 +1292,63 @@ Patch1206: 1206-core-when-removing-a-job-from-a-transaction-include-.patch
Patch1207: 1207-catalog-add-entries-for-the-order-cycle-log-messages.patch Patch1207: 1207-catalog-add-entries-for-the-order-cycle-log-messages.patch
Patch1208: 1208-tree-wide-check-more-log-message-format-in-log_struc.patch Patch1208: 1208-tree-wide-check-more-log-message-format-in-log_struc.patch
Patch1209: 1209-core-transaction-do-not-attempt-to-log-n-a-as-a-jour.patch Patch1209: 1209-core-transaction-do-not-attempt-to-log-n-a-as-a-jour.patch
Patch1210: 1210-Revert-boot-Use-EFI_BOOT_MANAGER_POLICY_PROTOCOL-to-.patch
Patch1211: 1211-boot-Use-correct-memory-type-for-allocations.patch
Patch1212: 1212-meson-etc-systemd-network-is-also-used-by-udevd.patch
Patch1213: 1213-sd-bus-make-bus_add_match_full-accept-timeout.patch
Patch1214: 1214-core-unit-add-get_timeout_start_usec-in-UnitVTable-a.patch
Patch1215: 1215-core-unit-increase-the-NameOwnerChanged-GetNameOwner.patch
Patch1216: 1216-core-sd-bus-drop-empty-lines-between-function-call-a.patch
Patch1217: 1217-core-do-not-disconnect-from-bus-when-failed-to-insta.patch
Patch1218: 1218-dbus-stash-the-subscriber-list-when-we-disconenct-fr.patch
Patch1219: 1219-manager-s-deserialized_subscribed-subscribed_as_strv.patch
Patch1220: 1220-bus-util-do-not-reset-the-count-returned-by-sd_bus_t.patch
Patch1221: 1221-core-manager-restore-bus-track-deserialization-clean.patch
Patch1222: 1222-core-manager-drop-duplicate-bus-track-deserializatio.patch
Patch1223: 1223-sd-bus-bus-track-use-install_callback-in-sd_bus_trac.patch
Patch1224: 1224-shell-completion-add-kernel-identify-inspect-verbs-f.patch
Patch1225: 1225-test-add-tests-for-format_timestamp-and-parse_timest.patch
Patch1226: 1226-test-time-util-disable-failing-tests.patch
Patch1227: 1227-test-test-parse_timestamp-in-various-timezone.patch
Patch1228: 1228-systemctl-logind-add-missing-asserts.patch
Patch1229: 1229-systemctl-logind-make-logind_schedule_shutdown-accep.patch
Patch1230: 1230-systemctl-add-option-when-for-scheduled-shutdown.patch
Patch1231: 1231-test-time-util-add-test-cases-to-invalidate-show-and.patch
Patch1232: 1232-Introduce-RET_GATHER-and-use-it-in-src-shared.patch
Patch1233: 1233-fd-util-don-t-eat-up-errors-in-fd_cloexec_many.patch
Patch1234: 1234-sd-bus-refuse-to-send-messages-with-an-invalid-strin.patch
Patch1235: 1235-test-check-if-we-correctly-handle-invalid-UTF-8-in-m.patch
Patch1236: 1236-test-fix-a-typo-in-the-cleanup-stuff.patch
Patch1237: 1237-test-explicitly-specify-a-UTF-8-locale-for-UTF-8-she.patch
Patch1238: 1238-test-use-the-correct-file-name-when-restoring-the-or.patch
Patch1239: 1239-core-escape-UTF-8-in-mount-unit-Where-field-before-s.patch
Patch1240: 1240-Revert-test-time-util-disable-failing-tests.patch
Patch1241: 1241-test-use-get_timezones-to-iterate-all-known-timezone.patch
Patch1242: 1242-test-time-util-do-not-fail-on-DST-change.patch
Patch1243: 1243-test-time-util-suppress-timestamp-conversion-failure.patch
Patch1244: 1244-test-time-util-do-more-suppression-of-time-zone-chec.patch
Patch1245: 1245-test-time-util-fix-truncation-of-usec-to-sec.patch
Patch1246: 1246-test-unset-TZ-before-timezone-sensitive-unit-tests-a.patch
Patch1247: 1247-meson-extend-timeout-for-test-time-util.patch
Patch1248: 1248-time-util-use-DEFINE_STRING_TABLE_LOOKUP_TO_STRING-m.patch
Patch1249: 1249-time-util-align-string-table.patch
Patch1250: 1250-time-util-rename-variables.patch
Patch1251: 1251-time-util-add-assertions.patch
Patch1252: 1252-time-util-drop-redundant-else.patch
Patch1253: 1253-time-util-do-not-use-strdupa.patch
Patch1254: 1254-time-util-use-result-from-startswith_no_case.patch
Patch1255: 1255-time-util-use-usec_add-and-usec_sub_unsigned.patch
Patch1256: 1256-time-util-shorten-code-a-bit.patch
Patch1257: 1257-time-util-rename-variables.patch
Patch1258: 1258-time-util-drop-unnecessary-assignment-of-timezone-na.patch
Patch1259: 1259-time-util-make-parse_timestamp-use-the-RFC-822-ISO-8.patch
Patch1260: 1260-time-util-fix-typo.patch
Patch1261: 1261-ci-bump-the-tools-tree-to-F42.patch
Patch1262: 1262-journald-extend-STDOUT_STREAMS_MAX-to-64k.patch
Patch1263: 1263-Revert-Revert-udev-builtin-net_id-use-firmware_node-.patch
Patch1264: 1264-udev-builtin-net_id-ignore-firmware_node-sun-0.patch
Patch1265: 1265-fundamental-fix-compile-check-for-explicit_bzero.patch
Patch1266: 1266-time-util-make-USEC_TIMESTAMP_FORMATTABLE_MAX-for-32.patch
# Downstream-only patches (90009999) # Downstream-only patches (90009999)
@ -2169,6 +2226,65 @@ systemd-hwdb update &>/dev/null || :
%{_prefix}/lib/dracut/modules.d/70rhel-net-naming-sysattrs/* %{_prefix}/lib/dracut/modules.d/70rhel-net-naming-sysattrs/*
%changelog %changelog
* Tue Sep 16 2025 systemd maintenance team <systemd-maint@redhat.com> - 252-57
- Revert "boot: Use EFI_BOOT_MANAGER_POLICY_PROTOCOL to connect console devices" (RHEL-108596)
- boot: Use correct memory type for allocations (RHEL-108555)
- meson: /etc/systemd/network is also used by udevd (RHEL-109096)
- sd-bus: make bus_add_match_full accept timeout (RHEL-31756)
- core/unit: add get_timeout_start_usec in UnitVTable and define it for service (RHEL-31756)
- core/unit: increase the NameOwnerChanged/GetNameOwner timeout to the unit's start timeout (RHEL-31756)
- core,sd-bus: drop empty lines between function call and error check (RHEL-31756)
- core: do not disconnect from bus when failed to install signal match (RHEL-31756)
- dbus: stash the subscriber list when we disconenct from the bus (RHEL-31756)
- manager: s/deserialized_subscribed/subscribed_as_strv (RHEL-31756)
- bus-util: do not reset the count returned by sd_bus_track_count_name() (RHEL-31756)
- core/manager: restore bus track deserialization cleanup in manager_reload() (RHEL-31756)
- core/manager: drop duplicate bus track deserialization (RHEL-31756)
- sd-bus/bus-track: use install_callback in sd_bus_track_add_name() (RHEL-31756)
- shell completion: add kernel-identify/inspect verbs for bootctl (RHEL-108576)
- test: add tests for format_timestamp() and parse_timestamp() with various timezone (RHEL-109488)
- test-time-util: disable failing tests (RHEL-109488)
- test: test parse_timestamp() in various timezone (RHEL-109488)
- systemctl: logind: add missing asserts (RHEL-109488)
- systemctl: logind: make logind_schedule_shutdown accept action as param (RHEL-109488)
- systemctl: add option --when for scheduled shutdown (RHEL-109488)
- test-time-util: add test cases to invalidate "show" and "cancel" (RHEL-109488)
- Introduce RET_GATHER and use it in src/shared/ (RHEL-108598)
- fd-util: don't eat up errors in fd_cloexec_many (RHEL-108598)
- sd-bus: refuse to send messages with an invalid string (RHEL-108584)
- test: check if we correctly handle invalid UTF-8 in mount stuff (RHEL-108584)
- test: fix a typo in the cleanup stuff (RHEL-108584)
- test: explicitly specify a UTF-8 locale for UTF-8 shenanigans (RHEL-108584)
- test: use the correct file name when restoring the original fstab (RHEL-108584)
- core: escape UTF-8 in mount unit Where field before sending to clients (RHEL-108584)
- Revert "test-time-util: disable failing tests" (RHEL-109488)
- test: use get_timezones() to iterate all known timezones (RHEL-109488)
- test-time-util: do not fail on DST change (RHEL-109488)
- test-time-util: suppress timestamp conversion failures for Africa/Khartoum timezone (RHEL-109488)
- test-time-util: do more suppression of time zone checks (RHEL-109488)
- test-time-util: fix truncation of usec to sec (RHEL-109488)
- test: unset TZ before timezone-sensitive unit tests are run (RHEL-109488)
- meson: extend timeout for test-time-util (RHEL-109488)
- time-util: use DEFINE_STRING_TABLE_LOOKUP_TO_STRING() macro (RHEL-109488)
- time-util: align string table (RHEL-109488)
- time-util: rename variables (RHEL-109488)
- time-util: add assertions (RHEL-109488)
- time-util: drop redundant else (RHEL-109488)
- time-util: do not use strdupa() (RHEL-109488)
- time-util: use result from startswith_no_case() (RHEL-109488)
- time-util: use usec_add() and usec_sub_unsigned() (RHEL-109488)
- time-util: shorten code a bit (RHEL-109488)
- time-util: rename variables (RHEL-109488)
- time-util: drop unnecessary assignment of timezone name (RHEL-109488)
- time-util: make parse_timestamp() use the RFC-822/ISO 8601 standard timezone spec (RHEL-109488)
- time-util: fix typo (RHEL-109488)
- ci: bump the tools tree to F42 (RHEL-109488)
- journald: extend STDOUT_STREAMS_MAX to 64k (RHEL-111065)
- Revert "Revert "udev-builtin-net_id: use firmware_node/sun for ID_NET_NAME_SLOT"" (RHEL-50103)
- udev-builtin-net_id: ignore firmware_node/sun == 0 (RHEL-50103)
- fundamental: fix compile check for explicit_bzero (RHEL-108568)
- time-util: make USEC_TIMESTAMP_FORMATTABLE_MAX for 32bit system off by one day (RHEL-109488)
* Fri Aug 15 2025 systemd maintenance team <systemd-maint@redhat.com> - 252-55 * Fri Aug 15 2025 systemd maintenance team <systemd-maint@redhat.com> - 252-55
- tree-wide: check more log message format in log_struct() and friends (RHEL-100353) - tree-wide: check more log message format in log_struct() and friends (RHEL-100353)
- build: add some coloring to --version output (RHEL-100353) - build: add some coloring to --version output (RHEL-100353)