systemd-252-21

Resolves: RHEL-13199,RHEL-5988,RHEL-6090
This commit is contained in:
Jan Macku 2023-12-11 15:54:06 +01:00
parent 2d3ff96397
commit 484e7cdd90
20 changed files with 2691 additions and 1 deletions

View File

@ -0,0 +1,30 @@
From a1bd733809ff01c64a8a304a45e57277a5a98463 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 8 Dec 2023 19:35:37 +0100
Subject: [PATCH] meson: fix installation of ukify
ln_s was added in upstream later on. It's not present in this branch.
Fixup for b98da2d9e7.
Related: RHEL-13199
---
meson.build | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/meson.build b/meson.build
index 936e612a01..e09c426a72 100644
--- a/meson.build
+++ b/meson.build
@@ -3868,9 +3868,9 @@ ukify = custom_target(
if want_ukify
public_programs += ukify
- meson.add_install_script(sh, '-c',
- ln_s.format(bindir / 'ukify',
- rootlibexecdir / 'ukify'))
+ meson.add_install_script(meson_make_symlink,
+ bindir / 'ukify',
+ rootlibexecdir / 'ukify')
endif
if want_tests != 'false' and want_kernel_install

View File

@ -0,0 +1,37 @@
From 81802cf297a05d202aae5de21673fcc7064f9b7d Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 28 Oct 2022 09:08:09 +0900
Subject: [PATCH] sd-id128: introduce id128_hash_ops_free
(cherry picked from commit 3e61656fab869bb40f019c38c3347885238294de)
Related: RHEL-5988
---
src/libsystemd/sd-id128/id128-util.c | 1 +
src/libsystemd/sd-id128/id128-util.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/src/libsystemd/sd-id128/id128-util.c b/src/libsystemd/sd-id128/id128-util.c
index 4f52c14f64..cef340f3bc 100644
--- a/src/libsystemd/sd-id128/id128-util.c
+++ b/src/libsystemd/sd-id128/id128-util.c
@@ -184,6 +184,7 @@ sd_id128_t id128_make_v4_uuid(sd_id128_t id) {
}
DEFINE_HASH_OPS(id128_hash_ops, sd_id128_t, id128_hash_func, id128_compare_func);
+DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(id128_hash_ops_free, sd_id128_t, id128_hash_func, id128_compare_func, free);
int id128_get_product(sd_id128_t *ret) {
sd_id128_t uuid;
diff --git a/src/libsystemd/sd-id128/id128-util.h b/src/libsystemd/sd-id128/id128-util.h
index 17b180c10c..9d8fe93641 100644
--- a/src/libsystemd/sd-id128/id128-util.h
+++ b/src/libsystemd/sd-id128/id128-util.h
@@ -30,6 +30,7 @@ int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync);
void id128_hash_func(const sd_id128_t *p, struct siphash *state);
int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) _pure_;
extern const struct hash_ops id128_hash_ops;
+extern const struct hash_ops id128_hash_ops_free;
sd_id128_t id128_make_v4_uuid(sd_id128_t id);

View File

@ -0,0 +1,104 @@
From 597c41edd3e94f2c16209359fbd8de7ed44225d7 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 28 Oct 2022 10:14:09 +0900
Subject: [PATCH] udevadm-trigger: allow to fallback without synthetic UUID
only first time
If a device is successfully triggered with synthetic UUID, then that means
the kernel support it. Hence, it is not necessary to fallback without UUID
for later devices.
(cherry picked from commit b15039425feba8f316fb306b75d96e2f0f0b82fa)
Related: RHEL-5988
---
src/udev/udevadm-trigger.c | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c
index 1d421064d7..cda31edd75 100644
--- a/src/udev/udevadm-trigger.c
+++ b/src/udev/udevadm-trigger.c
@@ -26,17 +26,20 @@ static bool arg_verbose = false;
static bool arg_dry_run = false;
static bool arg_quiet = false;
static bool arg_uuid = false;
+static bool arg_settle = false;
static int exec_list(
sd_device_enumerator *e,
sd_device_action_t action,
Hashmap *settle_hashmap) {
- bool skip_uuid_logic = false;
+ int uuid_supported = -1;
const char *action_str;
sd_device *d;
int r, ret = 0;
+ assert(e);
+
action_str = device_action_to_string(action);
FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
@@ -57,14 +60,14 @@ static int exec_list(
/* Use the UUID mode if the user explicitly asked for it, or if --settle has been specified,
* so that we can recognize our own uevent. */
- r = sd_device_trigger_with_uuid(d, action, (arg_uuid || settle_hashmap) && !skip_uuid_logic ? &id : NULL);
- if (r == -EINVAL && !arg_uuid && settle_hashmap && !skip_uuid_logic) {
+ r = sd_device_trigger_with_uuid(d, action, (arg_uuid || arg_settle) && uuid_supported != 0 ? &id : NULL);
+ if (r == -EINVAL && !arg_uuid && arg_settle && uuid_supported < 0) {
/* If we specified a UUID because of the settling logic, and we got EINVAL this might
* be caused by an old kernel which doesn't know the UUID logic (pre-4.13). Let's try
* if it works without the UUID logic then. */
r = sd_device_trigger(d, action);
if (r != -EINVAL)
- skip_uuid_logic = true; /* dropping the uuid stuff changed the return code,
+ uuid_supported = false; /* dropping the uuid stuff changed the return code,
* hence don't bother next time */
}
if (r < 0) {
@@ -108,11 +111,14 @@ static int exec_list(
continue;
}
+ if (uuid_supported < 0)
+ uuid_supported = true;
+
/* If the user asked for it, write event UUID to stdout */
if (arg_uuid)
printf(SD_ID128_UUID_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(id));
- if (settle_hashmap) {
+ if (arg_settle) {
_cleanup_free_ sd_id128_t *mid = NULL;
_cleanup_free_ char *sp = NULL;
@@ -285,7 +291,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_hashmap_free_ Hashmap *settle_hashmap = NULL;
usec_t ping_timeout_usec = 5 * USEC_PER_SEC;
- bool settle = false, ping = false;
+ bool ping = false;
int c, r;
if (running_in_chroot() > 0) {
@@ -389,7 +395,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
break;
}
case 'w':
- settle = true;
+ arg_settle = true;
break;
case ARG_NAME: {
@@ -477,7 +483,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
return log_error_errno(r, "Failed to add parent match '%s': %m", argv[optind]);
}
- if (settle) {
+ if (arg_settle) {
settle_hashmap = hashmap_new(&path_hash_ops_free_free);
if (!settle_hashmap)
return log_oom();

View File

@ -0,0 +1,196 @@
From 73dbfdaab1d633e3a1ae96cc15c551eaa2fd4243 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 28 Oct 2022 10:21:57 +0900
Subject: [PATCH] udevadm-trigger: settle with synthetic UUID if the kernel
support it
If the kernel support synthetic UUID in uevent, then let's assume that
the UUID is unique, and check only if the received UUID matches we
specified.
Partially fixes #25115.
(cherry picked from commit dfbd824a0b780310d7f865a6ea0d60434d924683)
Related: RHEL-5988
---
src/udev/udevadm-trigger.c | 82 +++++++++++++++++++-------------------
1 file changed, 40 insertions(+), 42 deletions(-)
diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c
index cda31edd75..3909fa237c 100644
--- a/src/udev/udevadm-trigger.c
+++ b/src/udev/udevadm-trigger.c
@@ -11,10 +11,12 @@
#include "device-util.h"
#include "fd-util.h"
#include "fileio.h"
+#include "id128-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
#include "set.h"
+#include "static-destruct.h"
#include "string-util.h"
#include "strv.h"
#include "udevadm.h"
@@ -31,8 +33,9 @@ static bool arg_settle = false;
static int exec_list(
sd_device_enumerator *e,
sd_device_action_t action,
- Hashmap *settle_hashmap) {
+ Set **ret_settle_path_or_ids) {
+ _cleanup_set_free_ Set *settle_path_or_ids = NULL;
int uuid_supported = -1;
const char *action_str;
sd_device *d;
@@ -119,60 +122,62 @@ static int exec_list(
printf(SD_ID128_UUID_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(id));
if (arg_settle) {
- _cleanup_free_ sd_id128_t *mid = NULL;
- _cleanup_free_ char *sp = NULL;
+ if (uuid_supported) {
+ sd_id128_t *dup;
- sp = strdup(syspath);
- if (!sp)
- return log_oom();
+ dup = newdup(sd_id128_t, &id, 1);
+ if (!dup)
+ return log_oom();
- mid = newdup(sd_id128_t, &id, 1);
- if (!d)
- return log_oom();
+ r = set_ensure_consume(&settle_path_or_ids, &id128_hash_ops_free, dup);
+ } else {
+ char *dup;
+
+ dup = strdup(syspath);
+ if (!dup)
+ return log_oom();
- r = hashmap_put(settle_hashmap, sp, mid);
+ r = set_ensure_consume(&settle_path_or_ids, &path_hash_ops_free, dup);
+ }
if (r < 0)
return log_oom();
-
- TAKE_PTR(sp);
- TAKE_PTR(mid);
}
}
+ if (ret_settle_path_or_ids)
+ *ret_settle_path_or_ids = TAKE_PTR(settle_path_or_ids);
+
return ret;
}
static int device_monitor_handler(sd_device_monitor *m, sd_device *dev, void *userdata) {
- Hashmap *settle_hashmap = ASSERT_PTR(userdata);
- sd_id128_t *settle_id;
+ Set *settle_path_or_ids = * (Set**) ASSERT_PTR(userdata);
const char *syspath;
- char *k;
+ sd_id128_t id;
int r;
assert(dev);
r = sd_device_get_syspath(dev, &syspath);
if (r < 0) {
- log_debug_errno(r, "Failed to get syspath of device event, ignoring: %m");
+ log_device_debug_errno(dev, r, "Failed to get syspath of device event, ignoring: %m");
return 0;
}
- settle_id = hashmap_get2(settle_hashmap, syspath, (void**) &k);
- if (!settle_id) {
- log_debug("Got uevent for unexpected device '%s', ignoring.", syspath);
- return 0;
- }
- if (!sd_id128_is_null(*settle_id)) { /* If this is SD_ID128_NULL then we are on pre-4.13 and have no UUID to check, hence don't */
- sd_id128_t event_id;
+ if (sd_device_get_trigger_uuid(dev, &id) >= 0) {
+ _cleanup_free_ sd_id128_t *saved = NULL;
- r = sd_device_get_trigger_uuid(dev, &event_id);
- if (r < 0) {
- log_debug_errno(r, "Got uevent without synthetic UUID for device '%s', ignoring: %m", syspath);
+ saved = set_remove(settle_path_or_ids, &id);
+ if (!saved) {
+ log_device_debug(dev, "Got uevent not matching expected UUID, ignoring.");
return 0;
}
+ } else {
+ _cleanup_free_ char *saved = NULL;
- if (!sd_id128_equal(event_id, *settle_id)) {
- log_debug("Got uevent not matching expected UUID for device '%s', ignoring.", syspath);
+ saved = set_remove(settle_path_or_ids, syspath);
+ if (!saved) {
+ log_device_debug(dev, "Got uevent for unexpected device, ignoring.");
return 0;
}
}
@@ -181,12 +186,9 @@ static int device_monitor_handler(sd_device_monitor *m, sd_device *dev, void *us
printf("settle %s\n", syspath);
if (arg_uuid)
- printf("settle " SD_ID128_UUID_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(*settle_id));
+ printf("settle " SD_ID128_UUID_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(id));
- free(hashmap_remove(settle_hashmap, syspath));
- free(k);
-
- if (hashmap_isempty(settle_hashmap))
+ if (set_isempty(settle_path_or_ids))
return sd_event_exit(sd_device_monitor_get_event(m), 0);
return 0;
@@ -289,7 +291,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
- _cleanup_hashmap_free_ Hashmap *settle_hashmap = NULL;
+ _cleanup_set_free_ Set *settle_path_or_ids = NULL;
usec_t ping_timeout_usec = 5 * USEC_PER_SEC;
bool ping = false;
int c, r;
@@ -484,10 +486,6 @@ int trigger_main(int argc, char *argv[], void *userdata) {
}
if (arg_settle) {
- settle_hashmap = hashmap_new(&path_hash_ops_free_free);
- if (!settle_hashmap)
- return log_oom();
-
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to get default event: %m");
@@ -500,7 +498,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to attach event to device monitor: %m");
- r = sd_device_monitor_start(m, device_monitor_handler, settle_hashmap);
+ r = sd_device_monitor_start(m, device_monitor_handler, &settle_path_or_ids);
if (r < 0)
return log_error_errno(r, "Failed to start device monitor: %m");
}
@@ -525,11 +523,11 @@ int trigger_main(int argc, char *argv[], void *userdata) {
assert_not_reached();
}
- r = exec_list(e, action, settle_hashmap);
+ r = exec_list(e, action, arg_settle ? &settle_path_or_ids : NULL);
if (r < 0)
return r;
- if (event && !hashmap_isempty(settle_hashmap)) {
+ if (!set_isempty(settle_path_or_ids)) {
r = sd_event_loop(event);
if (r < 0)
return log_error_errno(r, "Event loop failed: %m");

View File

@ -0,0 +1,56 @@
From 4007f494b2e4c45f2d59948af3f4053258d3f127 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 28 Oct 2022 09:06:02 +0900
Subject: [PATCH] udevadm-trigger: also check with the original syspath if
device is renamed
For older kernels that synthetic UUID is not supported, we need to also
check the original device name, as udevd broadcasts uevent with new
sysname.
Fixes #25115.
(cherry picked from commit 1193448cb68e5a90cab027e16a093bbd367e9494)
Related: RHEL-5988
---
src/udev/udevadm-trigger.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c
index 3909fa237c..40ee5085a0 100644
--- a/src/udev/udevadm-trigger.c
+++ b/src/udev/udevadm-trigger.c
@@ -176,6 +176,32 @@ static int device_monitor_handler(sd_device_monitor *m, sd_device *dev, void *us
_cleanup_free_ char *saved = NULL;
saved = set_remove(settle_path_or_ids, syspath);
+ if (!saved) {
+ const char *old_sysname;
+
+ /* When the device is renamed, the new name is broadcast, and the old name is saved
+ * in INTERFACE_OLD. */
+
+ if (sd_device_get_property_value(dev, "INTERFACE_OLD", &old_sysname) >= 0) {
+ _cleanup_free_ char *dir = NULL, *old_syspath = NULL;
+
+ r = path_extract_directory(syspath, &dir);
+ if (r < 0) {
+ log_device_debug_errno(dev, r,
+ "Failed to extract directory from '%s', ignoring: %m",
+ syspath);
+ return 0;
+ }
+
+ old_syspath = path_join(dir, old_sysname);
+ if (!old_syspath) {
+ log_oom_debug();
+ return 0;
+ }
+
+ saved = set_remove(settle_path_or_ids, old_syspath);
+ }
+ }
if (!saved) {
log_device_debug(dev, "Got uevent for unexpected device, ignoring.");
return 0;

View File

@ -0,0 +1,37 @@
From ff755f035485eab0317d1320caa2748d5d4a2d78 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 27 Oct 2022 05:48:05 +0900
Subject: [PATCH] test: use 'udevadm trigger --settle' even if device is
renamed
(cherry picked from commit ff4d2a09fd141474cb552d4b5bd5a53d9748a1b4)
Related: RHEL-5988
---
test/units/testsuite-17.02.sh | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/test/units/testsuite-17.02.sh b/test/units/testsuite-17.02.sh
index ed3b39d074..82f9fd1f62 100755
--- a/test/units/testsuite-17.02.sh
+++ b/test/units/testsuite-17.02.sh
@@ -61,9 +61,7 @@ EOF
udevadm control --log-priority=debug --reload --timeout=30
-# FIXME(?): the 'add' uevent is broadcast as for 'foobar', instead of 'hoge'. Hence, we cannot use --settle here.
-# See issue #25115.
-udevadm trigger --action=add /sys/devices/virtual/net/hoge
+udevadm trigger --action=add --settle /sys/devices/virtual/net/hoge
udevadm wait --timeout=30 --settle /sys/devices/virtual/net/foobar
assert_not_in "ID_RENAMING=" "$(udevadm info /sys/devices/virtual/net/foobar)"
timeout 30 bash -c 'while [[ "$(systemctl show --property=ActiveState --value /sys/devices/virtual/net/hoge)" != "inactive" ]]; do sleep .5; done'
@@ -71,7 +69,7 @@ timeout 30 bash -c 'while [[ "$(systemctl show --property=ActiveState --value /s
timeout 30 bash -c 'while [[ "$(systemctl show --property=ActiveState --value /sys/devices/virtual/net/foobar)" != "active" ]]; do sleep .5; done'
timeout 30 bash -c 'while [[ "$(systemctl show --property=ActiveState --value /sys/subsystem/net/devices/foobar)" != "active" ]]; do sleep .5; done'
-udevadm trigger --action=add /sys/devices/virtual/net/foobar
+udevadm trigger --action=add --settle /sys/devices/virtual/net/foobar
udevadm wait --timeout=30 --settle /sys/devices/virtual/net/hoge
assert_not_in "ID_RENAMING=" "$(udevadm info /sys/devices/virtual/net/hoge)"
timeout 30 bash -c 'while [[ "$(systemctl show --property=ActiveState --value /sys/devices/virtual/net/hoge)" != "active" ]]; do sleep .5; done'

View File

@ -0,0 +1,33 @@
From e92c85b68932845c908cb3f38b2130c57065e263 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 6 Jan 2023 11:27:17 +0100
Subject: [PATCH] sd-event: don't mistake USEC_INFINITY passed in for overflow
Let's pass USEC_INFINITY from sd_event_source_set_time_relative() to
sd_event_source_set_time() instead of raising EOVERFLOW.
We should raise EOVERFLOW only if your addition fails, but not if the
input already is USEC_INFINITY, since it's an entirely valid operation
to have an infinite time-out, and we should support that.
(cherry picked from commit ef8591951aefccb668201f24aa481aa6cda834da)
Related: RHEL-6090
---
src/libsystemd/sd-event/sd-event.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 778070a5fb..cd73cd8bfd 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -2723,6 +2723,9 @@ _public_ int sd_event_source_set_time_relative(sd_event_source *s, uint64_t usec
assert_return(s, -EINVAL);
assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM);
+ if (usec == USEC_INFINITY)
+ return sd_event_source_set_time(s, USEC_INFINITY);
+
r = sd_event_now(s->event, event_source_type_to_clock(s->type), &t);
if (r < 0)
return r;

View File

@ -0,0 +1,118 @@
From 917b03f2b5ccdd668a49da7df72baaddd338c071 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 15:06:10 +0100
Subject: [PATCH] pid1: rework service_arm_timer() to optionally take a
relative time value
In most cases this is actually what we want, hence simplify this case.
(cherry picked from commit e5d6dcce7f852b978251d062afb2fcba16714eb9)
Related: RHEL-6090
---
src/core/service.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/core/service.c b/src/core/service.c
index 1e14cdc6ca..aa76b4ad9a 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -530,13 +530,13 @@ static usec_t service_running_timeout(Service *s) {
delta);
}
-static int service_arm_timer(Service *s, usec_t usec) {
+static int service_arm_timer(Service *s, bool relative, usec_t usec) {
int r;
assert(s);
if (s->timer_event_source) {
- r = sd_event_source_set_time(s->timer_event_source, usec);
+ r = (relative ? sd_event_source_set_time_relative : sd_event_source_set_time)(s->timer_event_source, usec);
if (r < 0)
return r;
@@ -546,7 +546,7 @@ static int service_arm_timer(Service *s, usec_t usec) {
if (usec == USEC_INFINITY)
return 0;
- r = sd_event_add_time(
+ r = (relative ? sd_event_add_time_relative : sd_event_add_time)(
UNIT(s)->manager->event,
&s->timer_event_source,
CLOCK_MONOTONIC,
@@ -1195,7 +1195,7 @@ static int service_coldplug(Unit *u) {
if (s->deserialized_state == s->state)
return 0;
- r = service_arm_timer(s, service_coldplug_timeout(s));
+ r = service_arm_timer(s, /* relative= */ false, service_coldplug_timeout(s));
if (r < 0)
return r;
@@ -1538,7 +1538,7 @@ static int service_spawn_internal(
return r;
}
- r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), timeout));
+ r = service_arm_timer(s, /* relative= */ true, timeout);
if (r < 0)
return r;
@@ -1857,7 +1857,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
if (s->will_auto_restart) {
s->will_auto_restart = false;
- r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->restart_usec));
+ r = service_arm_timer(s, /* relative= */ true, s->restart_usec);
if (r < 0) {
s->n_keep_fd_store--;
goto fail;
@@ -1989,8 +1989,8 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
goto fail;
if (r > 0) {
- r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC),
- kill_operation == KILL_WATCHDOG ? service_timeout_abort_usec(s) : s->timeout_stop_usec));
+ r = service_arm_timer(s, /* relative= */ true,
+ kill_operation == KILL_WATCHDOG ? service_timeout_abort_usec(s) : s->timeout_stop_usec);
if (r < 0)
goto fail;
@@ -2020,7 +2020,7 @@ static void service_enter_stop_by_notify(Service *s) {
(void) unit_enqueue_rewatch_pids(UNIT(s));
- service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec));
+ service_arm_timer(s, /* relative= */ true, s->timeout_stop_usec);
/* The service told us it's stopping, so it's as if we SIGTERM'd it. */
service_set_state(s, SERVICE_STOP_SIGTERM);
@@ -2099,7 +2099,7 @@ static void service_enter_running(Service *s, ServiceResult f) {
service_enter_stop_by_notify(s);
else {
service_set_state(s, SERVICE_RUNNING);
- service_arm_timer(s, service_running_timeout(s));
+ service_arm_timer(s, /* relative= */ false, service_running_timeout(s));
}
} else if (s->remain_after_exit)
@@ -2398,7 +2398,7 @@ static void service_enter_reload_by_notify(Service *s) {
assert(s);
- service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_start_usec));
+ service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
service_set_state(s, SERVICE_RELOAD);
/* service_enter_reload_by_notify is never called during a reload, thus no loops are possible. */
@@ -4570,7 +4570,7 @@ static int service_clean(Unit *u, ExecCleanMask mask) {
s->control_command = NULL;
s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
- r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->exec_context.timeout_clean_usec));
+ r = service_arm_timer(s, /* relative= */ true, s->exec_context.timeout_clean_usec);
if (r < 0)
goto fail;

View File

@ -0,0 +1,25 @@
From efe1737efae0950b7ded32d9c5e1a9cfaea7296b Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 15:00:05 +0100
Subject: [PATCH] manager: add one more assert()
(cherry picked from commit 7fa49280bc33ba5135228401fb24dce0de5f9195)
Related: RHEL-6090
---
src/core/manager.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/core/manager.c b/src/core/manager.c
index 657263eb73..6371810ce3 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -806,6 +806,8 @@ static int manager_find_credentials_dirs(Manager *m) {
}
void manager_set_switching_root(Manager *m, bool switching_root) {
+ assert(m);
+
m->switching_root = MANAGER_IS_SYSTEM(m) && switching_root;
}

View File

@ -0,0 +1,688 @@
From f64d331351e33199c4096b2ae4a4b9d24d127661 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 16:49:23 +0100
Subject: [PATCH] pid1: add new Type=notify-reload service type
Fixes: #6162
(cherry picked from commit 3bd28bf721dc70722ff1c675026ed0b44ad968a3)
Resolves: RHEL-6090
---
man/org.freedesktop.systemd1.xml | 6 +
src/basic/unit-def.c | 2 +
src/basic/unit-def.h | 4 +-
src/core/dbus-service.c | 5 +
src/core/load-fragment-gperf.gperf.in | 1 +
src/core/service.c | 226 ++++++++++++++++++--------
src/core/service.h | 18 +-
src/shared/bus-unit-util.c | 3 +-
8 files changed, 189 insertions(+), 76 deletions(-)
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
index 13a84af747..c18428a092 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -2570,6 +2570,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
readonly u NRestarts = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s OOMPolicy = '...';
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly i ReloadSignal = ...;
readonly t ExecMainStartTimestamp = ...;
readonly t ExecMainStartTimestampMonotonic = ...;
readonly t ExecMainExitTimestamp = ...;
@@ -3163,6 +3165,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<!--property OOMPolicy is not documented!-->
+ <!--property ReloadSignal is not documented!-->
+
<!--property ExecCondition is not documented!-->
<!--property ExecConditionEx is not documented!-->
@@ -3715,6 +3719,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<variablelist class="dbus-property" generated="True" extra-ref="OOMPolicy"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="ReloadSignal"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="ExecMainStartTimestamp"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExecMainStartTimestampMonotonic"/>
diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c
index 94cd603e32..bdb1860246 100644
--- a/src/basic/unit-def.c
+++ b/src/basic/unit-def.c
@@ -188,6 +188,8 @@ static const char* const service_state_table[_SERVICE_STATE_MAX] = {
[SERVICE_RUNNING] = "running",
[SERVICE_EXITED] = "exited",
[SERVICE_RELOAD] = "reload",
+ [SERVICE_RELOAD_SIGNAL] = "reload-signal",
+ [SERVICE_RELOAD_NOTIFY] = "reload-notify",
[SERVICE_STOP] = "stop",
[SERVICE_STOP_WATCHDOG] = "stop-watchdog",
[SERVICE_STOP_SIGTERM] = "stop-sigterm",
diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h
index 5fcd51c095..bae132ea09 100644
--- a/src/basic/unit-def.h
+++ b/src/basic/unit-def.h
@@ -132,7 +132,9 @@ typedef enum ServiceState {
SERVICE_START_POST,
SERVICE_RUNNING,
SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */
- SERVICE_RELOAD,
+ SERVICE_RELOAD, /* Reloading via ExecReload= */
+ SERVICE_RELOAD_SIGNAL, /* Reloading via SIGHUP requested */
+ SERVICE_RELOAD_NOTIFY, /* Waiting for READY=1 after RELOADING=1 notify */
SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */
SERVICE_STOP_WATCHDOG,
SERVICE_STOP_SIGTERM,
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index 6e4bc0bd1a..3d130db66a 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -228,6 +228,7 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("NRestarts", "u", bus_property_get_unsigned, offsetof(Service, n_restarts), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("OOMPolicy", "s", bus_property_get_oom_policy, offsetof(Service, oom_policy), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("ReloadSignal", "i", bus_property_get_int, offsetof(Service, reload_signal), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_EXEC_STATUS_VTABLE("ExecMain", offsetof(Service, main_exec_status), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecCondition", offsetof(Service, exec_command[SERVICE_EXEC_CONDITION]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
@@ -374,6 +375,7 @@ static BUS_DEFINE_SET_TRANSIENT_PARSE(service_restart, ServiceRestart, service_r
static BUS_DEFINE_SET_TRANSIENT_PARSE(oom_policy, OOMPolicy, oom_policy_from_string);
static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(bus_name, sd_bus_service_name_is_valid);
static BUS_DEFINE_SET_TRANSIENT_PARSE(timeout_failure_mode, ServiceTimeoutFailureMode, service_timeout_failure_mode_from_string);
+static BUS_DEFINE_SET_TRANSIENT_TO_STRING(reload_signal, "i", int32_t, int, "%" PRIi32, signal_to_string_with_check);
static int bus_service_set_transient_property(
Service *s,
@@ -532,6 +534,9 @@ static int bus_service_set_transient_property(
if (streq(name, "StandardErrorFileDescriptor"))
return bus_set_transient_std_fd(u, name, &s->stderr_fd, &s->exec_context.stdio_as_fds, message, flags, error);
+ if (streq(name, "ReloadSignal"))
+ return bus_set_transient_reload_signal(u, name, &s->reload_signal, message, flags, error);
+
return 0;
}
diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in
index 81a5971339..53089d5590 100644
--- a/src/core/load-fragment-gperf.gperf.in
+++ b/src/core/load-fragment-gperf.gperf.in
@@ -424,6 +424,7 @@ Service.BusPolicy, config_parse_warn_compat,
Service.USBFunctionDescriptors, config_parse_unit_path_printf, 0, offsetof(Service, usb_function_descriptors)
Service.USBFunctionStrings, config_parse_unit_path_printf, 0, offsetof(Service, usb_function_strings)
Service.OOMPolicy, config_parse_oom_policy, 0, offsetof(Service, oom_policy)
+Service.ReloadSignal, config_parse_signal, 0, offsetof(Service, reload_signal)
{{ EXEC_CONTEXT_CONFIG_ITEMS('Service') }}
{{ CGROUP_CONTEXT_CONFIG_ITEMS('Service') }}
{{ KILL_CONTEXT_CONFIG_ITEMS('Service') }}
diff --git a/src/core/service.c b/src/core/service.c
index aa76b4ad9a..902948905f 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -54,6 +54,8 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
[SERVICE_RUNNING] = UNIT_ACTIVE,
[SERVICE_EXITED] = UNIT_ACTIVE,
[SERVICE_RELOAD] = UNIT_RELOADING,
+ [SERVICE_RELOAD_SIGNAL] = UNIT_RELOADING,
+ [SERVICE_RELOAD_NOTIFY] = UNIT_RELOADING,
[SERVICE_STOP] = UNIT_DEACTIVATING,
[SERVICE_STOP_WATCHDOG] = UNIT_DEACTIVATING,
[SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
@@ -78,6 +80,8 @@ static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] =
[SERVICE_RUNNING] = UNIT_ACTIVE,
[SERVICE_EXITED] = UNIT_ACTIVE,
[SERVICE_RELOAD] = UNIT_RELOADING,
+ [SERVICE_RELOAD_SIGNAL] = UNIT_RELOADING,
+ [SERVICE_RELOAD_NOTIFY] = UNIT_RELOADING,
[SERVICE_STOP] = UNIT_DEACTIVATING,
[SERVICE_STOP_WATCHDOG] = UNIT_DEACTIVATING,
[SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
@@ -124,6 +128,8 @@ static void service_init(Unit *u) {
s->watchdog_original_usec = USEC_INFINITY;
s->oom_policy = _OOM_POLICY_INVALID;
+ s->reload_begin_usec = USEC_INFINITY;
+ s->reload_signal = SIGHUP;
}
static void service_unwatch_control_pid(Service *s) {
@@ -765,7 +771,7 @@ static int service_add_extras(Service *s) {
/* If the service needs the notify socket, let's enable it automatically. */
if (s->notify_access == NOTIFY_NONE &&
- (s->type == SERVICE_NOTIFY || s->watchdog_usec > 0 || s->n_fd_store_max > 0))
+ (IN_SET(s->type, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD) || s->watchdog_usec > 0 || s->n_fd_store_max > 0))
s->notify_access = NOTIFY_MAIN;
/* If no OOM policy was explicitly set, then default to the configure default OOM policy. Except when
@@ -830,7 +836,8 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
"%sRestart: %s\n"
"%sNotifyAccess: %s\n"
"%sNotifyState: %s\n"
- "%sOOMPolicy: %s\n",
+ "%sOOMPolicy: %s\n"
+ "%sReloadSignal: %s\n",
prefix, service_state_to_string(s->state),
prefix, service_result_to_string(s->result),
prefix, service_result_to_string(s->reload_result),
@@ -843,7 +850,8 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
prefix, service_restart_to_string(s->restart),
prefix, notify_access_to_string(s->notify_access),
prefix, notify_state_to_string(s->notify_state),
- prefix, oom_policy_to_string(s->oom_policy));
+ prefix, oom_policy_to_string(s->oom_policy),
+ prefix, signal_to_string(s->reload_signal));
if (s->control_pid > 0)
fprintf(f,
@@ -1088,7 +1096,7 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state,
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING,
- SERVICE_RELOAD,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_AUTO_RESTART,
@@ -1097,7 +1105,8 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state,
SERVICE_START, SERVICE_START_POST,
- SERVICE_RUNNING, SERVICE_RELOAD,
+ SERVICE_RUNNING,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
service_unwatch_main_pid(s);
@@ -1106,7 +1115,7 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state,
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RELOAD,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_CLEANING)) {
@@ -1122,7 +1131,8 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state,
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RUNNING, SERVICE_RELOAD,
+ SERVICE_RUNNING,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
!(state == SERVICE_DEAD && UNIT(s)->job))
@@ -1131,7 +1141,7 @@ static void service_set_state(Service *s, ServiceState state) {
if (state != SERVICE_START)
s->exec_fd_event_source = sd_event_source_disable_unref(s->exec_fd_event_source);
- if (!IN_SET(state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
+ if (!IN_SET(state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY))
service_stop_watchdog(s);
/* For the inactive states unit_notify() will trim the cgroup,
@@ -1157,6 +1167,8 @@ static usec_t service_coldplug_timeout(Service *s) {
case SERVICE_START:
case SERVICE_START_POST:
case SERVICE_RELOAD:
+ case SERVICE_RELOAD_SIGNAL:
+ case SERVICE_RELOAD_NOTIFY:
return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_start_usec);
case SERVICE_RUNNING:
@@ -1203,7 +1215,8 @@ static int service_coldplug(Unit *u) {
pid_is_unwaited(s->main_pid) &&
(IN_SET(s->deserialized_state,
SERVICE_START, SERVICE_START_POST,
- SERVICE_RUNNING, SERVICE_RELOAD,
+ SERVICE_RUNNING,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
r = unit_watch_pid(UNIT(s), s->main_pid, false);
@@ -1215,7 +1228,7 @@ static int service_coldplug(Unit *u) {
pid_is_unwaited(s->control_pid) &&
IN_SET(s->deserialized_state,
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RELOAD,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_CLEANING)) {
@@ -1230,7 +1243,7 @@ static int service_coldplug(Unit *u) {
(void) unit_setup_exec_runtime(u);
}
- if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
+ if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY))
service_start_watchdog(s);
if (UNIT_ISSET(s->accept_socket)) {
@@ -2255,7 +2268,7 @@ static void service_enter_start(Service *s) {
s->control_pid = pid;
service_set_state(s, SERVICE_START);
- } else if (IN_SET(s->type, SERVICE_ONESHOT, SERVICE_DBUS, SERVICE_NOTIFY, SERVICE_EXEC)) {
+ } else if (IN_SET(s->type, SERVICE_ONESHOT, SERVICE_DBUS, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD, SERVICE_EXEC)) {
/* For oneshot services we wait until the start process exited, too, but it is our main process. */
@@ -2399,7 +2412,7 @@ static void service_enter_reload_by_notify(Service *s) {
assert(s);
service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
- service_set_state(s, SERVICE_RELOAD);
+ service_set_state(s, SERVICE_RELOAD_NOTIFY);
/* service_enter_reload_by_notify is never called during a reload, thus no loops are possible. */
r = manager_propagate_reload(UNIT(s)->manager, UNIT(s), JOB_FAIL, &error);
@@ -2408,6 +2421,7 @@ static void service_enter_reload_by_notify(Service *s) {
}
static void service_enter_reload(Service *s) {
+ bool killed = false;
int r;
assert(s);
@@ -2415,6 +2429,18 @@ static void service_enter_reload(Service *s) {
service_unwatch_control_pid(s);
s->reload_result = SERVICE_SUCCESS;
+ usec_t ts = now(CLOCK_MONOTONIC);
+
+ if (s->type == SERVICE_NOTIFY_RELOAD && s->main_pid > 0) {
+ r = kill_and_sigcont(s->main_pid, s->reload_signal);
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to send reload signal: %m");
+ goto fail;
+ }
+
+ killed = true;
+ }
+
s->control_command = s->exec_command[SERVICE_EXEC_RELOAD];
if (s->control_command) {
s->control_command_id = SERVICE_EXEC_RELOAD;
@@ -2424,17 +2450,28 @@ static void service_enter_reload(Service *s) {
s->timeout_start_usec,
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_CONTROL_CGROUP,
&s->control_pid);
- if (r < 0)
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to run 'reload' task: %m");
goto fail;
+ }
service_set_state(s, SERVICE_RELOAD);
- } else
+ } else if (killed) {
+ service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
+ service_set_state(s, SERVICE_RELOAD_SIGNAL);
+ } else {
service_enter_running(s, SERVICE_SUCCESS);
+ return;
+ }
+ /* Store the timestamp when we started reloading: when reloading via SIGHUP we won't leave the reload
+ * state until we received both RELOADING=1 and READY=1 with MONOTONIC_USEC= set to a value above
+ * this. Thus we know for sure the reload cycle was executed *after* we requested it, and is not one
+ * that was already in progress before. */
+ s->reload_begin_usec = ts;
return;
fail:
- log_unit_warning_errno(UNIT(s), r, "Failed to run 'reload' task: %m");
s->reload_result = SERVICE_FAILURE_RESOURCES;
service_enter_running(s, SERVICE_SUCCESS);
}
@@ -2597,9 +2634,8 @@ static int service_stop(Unit *u) {
return 0;
}
- /* If there's already something running we go directly into
- * kill mode. */
- if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD, SERVICE_STOP_WATCHDOG)) {
+ /* If there's already something running we go directly into kill mode. */
+ if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_STOP_WATCHDOG)) {
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
return 0;
}
@@ -2632,7 +2668,8 @@ _pure_ static bool service_can_reload(Unit *u) {
assert(s);
- return !!s->exec_command[SERVICE_EXEC_RELOAD];
+ return s->exec_command[SERVICE_EXEC_RELOAD] ||
+ s->type == SERVICE_NOTIFY_RELOAD;
}
static unsigned service_exec_command_index(Unit *u, ServiceExecCommand id, ExecCommand *current) {
@@ -2808,6 +2845,9 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
if (s->watchdog_original_usec != USEC_INFINITY)
(void) serialize_item_format(f, "watchdog-original-usec", USEC_FMT, s->watchdog_original_usec);
+ if (s->reload_begin_usec != USEC_INFINITY)
+ (void) serialize_item_format(f, "reload-begin-usec", USEC_FMT, s->reload_begin_usec);
+
return 0;
}
@@ -3146,6 +3186,10 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
log_unit_debug_errno(u, r, "Failed to parse serialized flush restart counter setting '%s': %m", value);
else
s->flush_n_restarts = r;
+ } else if (streq(key, "reload-begin-usec")) {
+ r = deserialize_usec(value, &s->reload_begin_usec);
+ if (r < 0)
+ log_unit_debug_errno(u, r, "Failed to parse serialized reload begin timestamp '%s', ignoring: %m", value);
} else
log_unit_debug(u, "Unknown serialization key: %s", key);
@@ -3349,7 +3393,7 @@ static void service_notify_cgroup_empty_event(Unit *u) {
* SIGCHLD for. */
case SERVICE_START:
- if (s->type == SERVICE_NOTIFY &&
+ if (IN_SET(s->type, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD) &&
main_pid_good(s) == 0 &&
control_pid_good(s) == 0) {
/* No chance of getting a ready notification anymore */
@@ -3553,17 +3597,19 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
} else {
s->main_command = NULL;
- /* Services with ExitType=cgroup do not act on main PID exiting,
- * unless the cgroup is already empty */
+ /* Services with ExitType=cgroup do not act on main PID exiting, unless the cgroup is
+ * already empty */
if (s->exit_type == SERVICE_EXIT_MAIN || cgroup_good(s) <= 0) {
/* The service exited, so the service is officially gone. */
switch (s->state) {
case SERVICE_START_POST:
case SERVICE_RELOAD:
- /* If neither main nor control processes are running then
- * the current state can never exit cleanly, hence immediately
- * terminate the service. */
+ case SERVICE_RELOAD_SIGNAL:
+ case SERVICE_RELOAD_NOTIFY:
+ /* If neither main nor control processes are running then the current
+ * state can never exit cleanly, hence immediately terminate the
+ * service. */
if (control_pid_good(s) <= 0)
service_enter_stop(s, f);
@@ -3582,7 +3628,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
else
service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
break;
- } else if (s->type == SERVICE_NOTIFY) {
+ } else if (IN_SET(s->type, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD)) {
/* Only enter running through a notification, so that the
* SERVICE_START state signifies that no ready notification
* has been received */
@@ -3675,15 +3721,13 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
s->control_command->command_next &&
f == SERVICE_SUCCESS) {
- /* There is another command to *
- * execute, so let's do that. */
+ /* There is another command to * execute, so let's do that. */
log_unit_debug(u, "Running next control command for state %s.", service_state_to_string(s->state));
service_run_next_control(s);
} else {
- /* No further commands for this step, so let's
- * figure out what to do next */
+ /* No further commands for this step, so let's figure out what to do next */
s->control_command = NULL;
s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
@@ -3761,12 +3805,22 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
break;
case SERVICE_RELOAD:
+ case SERVICE_RELOAD_SIGNAL:
+ case SERVICE_RELOAD_NOTIFY:
if (f == SERVICE_SUCCESS)
if (service_load_pid_file(s, true) < 0)
service_search_main_pid(s);
s->reload_result = f;
- service_enter_running(s, SERVICE_SUCCESS);
+
+ /* If the last notification we received from the service process indiciates
+ * we are still reloading, then don't leave reloading state just yet, just
+ * transition into SERVICE_RELOAD_NOTIFY, to wait for the READY=1 coming,
+ * too. */
+ if (s->notify_state == NOTIFY_RELOADING)
+ service_set_state(s, SERVICE_RELOAD_NOTIFY);
+ else
+ service_enter_running(s, SERVICE_SUCCESS);
break;
case SERVICE_STOP:
@@ -3869,6 +3923,8 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
break;
case SERVICE_RELOAD:
+ case SERVICE_RELOAD_SIGNAL:
+ case SERVICE_RELOAD_NOTIFY:
log_unit_warning(UNIT(s), "Reload operation timed out. Killing reload process.");
service_kill_control_process(s);
s->reload_result = SERVICE_FAILURE_TIMEOUT;
@@ -4094,6 +4150,7 @@ static void service_notify_message(
Service *s = SERVICE(u);
bool notify_dbus = false;
+ usec_t monotonic_usec = USEC_INFINITY;
const char *e;
int r;
@@ -4112,7 +4169,7 @@ static void service_notify_message(
/* Interpret MAINPID= */
e = strv_find_startswith(tags, "MAINPID=");
- if (e && IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) {
+ if (e && IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY)) {
pid_t new_main_pid;
if (parse_pid(e, &new_main_pid) < 0)
@@ -4141,43 +4198,73 @@ static void service_notify_message(
}
}
- /* Interpret READY=/STOPPING=/RELOADING=. Last one wins. */
- STRV_FOREACH_BACKWARDS(i, tags) {
+ /* Parse MONOTONIC_USEC= */
+ e = strv_find_startswith(tags, "MONOTONIC_USEC=");
+ if (e) {
+ r = safe_atou64(e, &monotonic_usec);
+ if (r < 0)
+ log_unit_warning_errno(u, r, "Failed to parse MONOTONIC_USEC= field in notification message, ignoring: %s", e);
+ }
- if (streq(*i, "READY=1")) {
- s->notify_state = NOTIFY_READY;
+ /* Interpret READY=/STOPPING=/RELOADING=. STOPPING= wins over the others, and READY= over RELOADING= */
+ if (strv_contains(tags, "STOPPING=1")) {
+ s->notify_state = NOTIFY_STOPPING;
- /* Type=notify services inform us about completed
- * initialization with READY=1 */
- if (s->type == SERVICE_NOTIFY && s->state == SERVICE_START)
- service_enter_start_post(s);
+ if (IN_SET(s->state, SERVICE_RUNNING, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY))
+ service_enter_stop_by_notify(s);
- /* Sending READY=1 while we are reloading informs us
- * that the reloading is complete */
- if (s->state == SERVICE_RELOAD && s->control_pid == 0)
- service_enter_running(s, SERVICE_SUCCESS);
+ notify_dbus = true;
- notify_dbus = true;
- break;
+ } else if (strv_contains(tags, "READY=1")) {
- } else if (streq(*i, "RELOADING=1")) {
- s->notify_state = NOTIFY_RELOADING;
+ s->notify_state = NOTIFY_READY;
- if (s->state == SERVICE_RUNNING)
- service_enter_reload_by_notify(s);
+ /* Type=notify services inform us about completed initialization with READY=1 */
+ if (IN_SET(s->type, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD) &&
+ s->state == SERVICE_START)
+ service_enter_start_post(s);
- notify_dbus = true;
- break;
+ /* Sending READY=1 while we are reloading informs us that the reloading is complete. */
+ if (s->state == SERVICE_RELOAD_NOTIFY)
+ service_enter_running(s, SERVICE_SUCCESS);
- } else if (streq(*i, "STOPPING=1")) {
- s->notify_state = NOTIFY_STOPPING;
+ /* Combined RELOADING=1 and READY=1? Then this is indication that the service started and
+ * immediately finished reloading. */
+ if (s->state == SERVICE_RELOAD_SIGNAL &&
+ strv_contains(tags, "RELOADING=1") &&
+ monotonic_usec != USEC_INFINITY &&
+ monotonic_usec >= s->reload_begin_usec) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- if (s->state == SERVICE_RUNNING)
- service_enter_stop_by_notify(s);
+ /* Propagate a reload explicitly */
+ r = manager_propagate_reload(UNIT(s)->manager, UNIT(s), JOB_FAIL, &error);
+ if (r < 0)
+ log_unit_warning(UNIT(s), "Failed to schedule propagation of reload, ignoring: %s", bus_error_message(&error, r));
- notify_dbus = true;
- break;
+ service_enter_running(s, SERVICE_SUCCESS);
}
+
+ notify_dbus = true;
+
+ } else if (strv_contains(tags, "RELOADING=1")) {
+
+ s->notify_state = NOTIFY_RELOADING;
+
+ /* Sending RELOADING=1 after we send SIGHUP to request a reload will transition
+ * things to "reload-notify" state, where we'll wait for READY=1 to let us know the
+ * reload is done. Note that we insist on a timestamp being sent along here, so that
+ * we know for sure this is a reload cycle initiated *after* we sent the signal */
+ if (s->state == SERVICE_RELOAD_SIGNAL &&
+ monotonic_usec != USEC_INFINITY &&
+ monotonic_usec >= s->reload_begin_usec)
+ /* Note, we don't call service_enter_reload_by_notify() here, because we
+ * don't need reload propagation nor do we want to restart the time-out. */
+ service_set_state(s, SERVICE_RELOAD_NOTIFY);
+
+ if (s->state == SERVICE_RUNNING)
+ service_enter_reload_by_notify(s);
+
+ notify_dbus = true;
}
/* Interpret STATUS= */
@@ -4307,7 +4394,9 @@ static bool pick_up_pid_from_bus_name(Service *s) {
SERVICE_START,
SERVICE_START_POST,
SERVICE_RUNNING,
- SERVICE_RELOAD);
+ SERVICE_RELOAD,
+ SERVICE_RELOAD_SIGNAL,
+ SERVICE_RELOAD_NOTIFY);
}
static int bus_name_pid_lookup_callback(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) {
@@ -4514,6 +4603,8 @@ static bool service_needs_console(Unit *u) {
SERVICE_START_POST,
SERVICE_RUNNING,
SERVICE_RELOAD,
+ SERVICE_RELOAD_SIGNAL,
+ SERVICE_RELOAD_NOTIFY,
SERVICE_STOP,
SERVICE_STOP_WATCHDOG,
SERVICE_STOP_SIGTERM,
@@ -4636,13 +4727,14 @@ static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart);
static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
- [SERVICE_SIMPLE] = "simple",
- [SERVICE_FORKING] = "forking",
- [SERVICE_ONESHOT] = "oneshot",
- [SERVICE_DBUS] = "dbus",
- [SERVICE_NOTIFY] = "notify",
- [SERVICE_IDLE] = "idle",
- [SERVICE_EXEC] = "exec",
+ [SERVICE_SIMPLE] = "simple",
+ [SERVICE_FORKING] = "forking",
+ [SERVICE_ONESHOT] = "oneshot",
+ [SERVICE_DBUS] = "dbus",
+ [SERVICE_NOTIFY] = "notify",
+ [SERVICE_NOTIFY_RELOAD] = "notify-reload",
+ [SERVICE_IDLE] = "idle",
+ [SERVICE_EXEC] = "exec",
};
DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
diff --git a/src/core/service.h b/src/core/service.h
index 91e02e6d7e..194067f0e1 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -24,13 +24,14 @@ typedef enum ServiceRestart {
} ServiceRestart;
typedef enum ServiceType {
- SERVICE_SIMPLE, /* we fork and go on right-away (i.e. modern socket activated daemons) */
- SERVICE_FORKING, /* forks by itself (i.e. traditional daemons) */
- SERVICE_ONESHOT, /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */
- SERVICE_DBUS, /* we fork and wait until a specific D-Bus name appears on the bus */
- SERVICE_NOTIFY, /* we fork and wait until a daemon sends us a ready message with sd_notify() */
- SERVICE_IDLE, /* much like simple, but delay exec() until all jobs are dispatched. */
- SERVICE_EXEC, /* we fork and wait until we execute exec() (this means our own setup is waited for) */
+ SERVICE_SIMPLE, /* we fork and go on right-away (i.e. modern socket activated daemons) */
+ SERVICE_FORKING, /* forks by itself (i.e. traditional daemons) */
+ SERVICE_ONESHOT, /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */
+ SERVICE_DBUS, /* we fork and wait until a specific D-Bus name appears on the bus */
+ SERVICE_NOTIFY, /* we fork and wait until a daemon sends us a ready message with sd_notify() */
+ SERVICE_NOTIFY_RELOAD, /* just like SERVICE_NOTIFY, but also implements a reload protocol via SIGHUP */
+ SERVICE_IDLE, /* much like simple, but delay exec() until all jobs are dispatched. */
+ SERVICE_EXEC, /* we fork and wait until we execute exec() (this means our own setup is waited for) */
_SERVICE_TYPE_MAX,
_SERVICE_TYPE_INVALID = -EINVAL,
} ServiceType;
@@ -215,6 +216,9 @@ struct Service {
bool flush_n_restarts;
OOMPolicy oom_policy;
+
+ int reload_signal;
+ usec_t reload_begin_usec;
};
static inline usec_t service_timeout_abort_usec(Service *s) {
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 922011eccd..a9844e1cc3 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -2065,7 +2065,8 @@ static int bus_append_kill_property(sd_bus_message *m, const char *field, const
if (STR_IN_SET(field, "KillSignal",
"RestartKillSignal",
"FinalKillSignal",
- "WatchdogSignal"))
+ "WatchdogSignal",
+ "ReloadSignal"))
return bus_append_signal_from_string(m, field, eq);
return 0;

View File

@ -0,0 +1,420 @@
From e8de964c146f67c91acdaff076420282c2d1b217 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 18:13:27 +0100
Subject: [PATCH] man: document Type=notify-reload
(cherry picked from commit 81e19b6f6585d656e972efad73781e184ca0e7a0)
Related: RHEL-6090
---
man/sd_notify.xml | 36 ++++--
man/systemd.service.xml | 248 ++++++++++++++++++++++------------------
2 files changed, 162 insertions(+), 122 deletions(-)
diff --git a/man/sd_notify.xml b/man/sd_notify.xml
index de402950bb..d2dba00004 100644
--- a/man/sd_notify.xml
+++ b/man/sd_notify.xml
@@ -102,23 +102,35 @@
<varlistentry>
<term>READY=1</term>
- <listitem><para>Tells the service manager that service startup is finished, or the service finished loading its
- configuration. This is only used by systemd if the service definition file has <varname>Type=notify</varname>
- set. Since there is little value in signaling non-readiness, the only value services should send is
- <literal>READY=1</literal> (i.e. <literal>READY=0</literal> is not defined).</para></listitem>
+ <listitem><para>Tells the service manager that service startup is finished, or the service finished
+ re-loading its configuration. This is only used by systemd if the service definition file has
+ <varname>Type=notify</varname> or <varname>Type=notify-reload</varname> set. Since there is little
+ value in signaling non-readiness, the only value services should send is <literal>READY=1</literal>
+ (i.e. <literal>READY=0</literal> is not defined).</para></listitem>
</varlistentry>
<varlistentry>
<term>RELOADING=1</term>
- <listitem><para>Tells the service manager that the service is
- reloading its configuration. This is useful to allow the
- service manager to track the service's internal state, and
- present it to the user. Note that a service that sends this
- notification must also send a <literal>READY=1</literal>
- notification when it completed reloading its
- configuration. Reloads are propagated in the same way as they
- are when initiated by the user.</para></listitem>
+ <listitem><para>Tells the service manager that the service is beginning to reload its
+ configuration. This is useful to allow the service manager to track the service's internal state, and
+ present it to the user. Note that a service that sends this notification must also send a
+ <literal>READY=1</literal> notification when it completed reloading its configuration. Reloads the
+ service manager is notified about with this mechanisms are propagated in the same way as they are
+ when originally initiated through the service manager. This message is particularly relevant for
+ <varname>Type=notify-reload</varname> services, to inform the service manager that the request to
+ reload the service has been received and is now being processed.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>MONOTONIC_USEC=…</term>
+
+ <listitem><para>A field carrying the monotonic timestamp (as per
+ <constant>CLOCK_MONOTONIC</constant>) formatted in decimal in µs, when the notification message was
+ generated by the client. This is typically used in combination with <literal>RELOADING=1</literal>,
+ to allow the service manager to properly synchronize reload cycles. See
+ <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for details, specifically <literal>Type=notify-reload</literal>.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index 1c9e59f722..ae54332440 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -157,7 +157,7 @@
<listitem>
<para>Configures the process start-up type for this service unit. One of <option>simple</option>,
<option>exec</option>, <option>forking</option>, <option>oneshot</option>, <option>dbus</option>,
- <option>notify</option> or <option>idle</option>:</para>
+ <option>notify</option>, <option>notify-reload</option> or <option>idle</option>:</para>
<itemizedlist>
<listitem><para>If set to <option>simple</option> (the default if <varname>ExecStart=</varname> is
@@ -216,14 +216,30 @@
logic thus should be prepared to receive a <constant>SIGTERM</constant> (or whichever signal is
configured in <varname>KillSignal=</varname>) as result.</para></listitem>
- <listitem><para>Behavior of <option>notify</option> is similar to <option>exec</option>; however, it is
- expected that the service sends a notification message via
- <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> or an
- equivalent call when it has finished starting up. systemd will proceed with starting follow-up units after
- this notification message has been sent. If this option is used, <varname>NotifyAccess=</varname> (see
- below) should be set to open access to the notification socket provided by systemd. If
- <varname>NotifyAccess=</varname> is missing or set to <option>none</option>, it will be forcibly set to
- <option>main</option>.</para></listitem>
+ <listitem><para>Behavior of <option>notify</option> is similar to <option>exec</option>; however,
+ it is expected that the service sends a <literal>READY=1</literal> notification message via
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> or
+ an equivalent call when it has finished starting up. systemd will proceed with starting follow-up
+ units after this notification message has been sent. If this option is used,
+ <varname>NotifyAccess=</varname> (see below) should be set to open access to the notification
+ socket provided by systemd. If <varname>NotifyAccess=</varname> is missing or set to
+ <option>none</option>, it will be forcibly set to <option>main</option>.</para></listitem>
+
+ <listitem><para>Behavior of <option>notify-reload</option> is identical to
+ <option>notify</option>. However, it extends the logic in one way: the
+ <constant>SIGHUP</constant> UNIX process signal is sent to the service's main process when the
+ service is asked to reload. (The signal to send can be tweaked via
+ <varname>ReloadSignal=</varname>, see below.). When
+ initiating the reload process the service is then expected to reply with a notification message
+ via <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ that contains the <literal>RELOADING=1</literal> field in combination with
+ <literal>MONOTONIC_USEC=</literal> set to the current monotonic time
+ (i.e. <constant>CLOCK_MONOTONIC</constant> in
+ <citerefentry><refentrytitle>clock_gettime</refentrytitle><manvolnum>2</manvolnum></citerefentry>)
+ in µs, formatted as decimal string. Once reloading is complete another notification message must
+ be sent, containing <literal>READY=1</literal>. Using this service type and implementing this
+ reload protocol is an efficient alternative to providing an <varname>ExecReload=</varname>
+ command for reloading of the service's configuration.</para></listitem>
<listitem><para>Behavior of <option>idle</option> is very similar to <option>simple</option>; however,
actual execution of the service program is delayed until all active jobs are dispatched. This may be used
@@ -233,25 +249,27 @@
anyway.</para></listitem>
</itemizedlist>
- <para>It is generally recommended to use <varname>Type=</varname><option>simple</option> for long-running
- services whenever possible, as it is the simplest and fastest option. However, as this service type won't
- propagate service start-up failures and doesn't allow ordering of other units against completion of
- initialization of the service (which for example is useful if clients need to connect to the service through
- some form of IPC, and the IPC channel is only established by the service itself — in contrast to doing this
- ahead of time through socket or bus activation or similar), it might not be sufficient for many cases. If so,
- <option>notify</option> or <option>dbus</option> (the latter only in case the service provides a D-Bus
- interface) are the preferred options as they allow service program code to precisely schedule when to
- consider the service started up successfully and when to proceed with follow-up units. The
- <option>notify</option> service type requires explicit support in the service codebase (as
- <function>sd_notify()</function> or an equivalent API needs to be invoked by the service at the appropriate
- time) — if it's not supported, then <option>forking</option> is an alternative: it supports the traditional
- UNIX service start-up protocol. Finally, <option>exec</option> might be an option for cases where it is
- enough to ensure the service binary is invoked, and where the service binary itself executes no or little
- initialization on its own (and its initialization is unlikely to fail). Note that using any type other than
- <option>simple</option> possibly delays the boot process, as the service manager needs to wait for service
- initialization to complete. It is hence recommended not to needlessly use any types other than
- <option>simple</option>. (Also note it is generally not recommended to use <option>idle</option> or
- <option>oneshot</option> for long-running services.)</para>
+ <para>It is generally recommended to use <varname>Type=</varname><option>simple</option> for
+ long-running services whenever possible, as it is the simplest and fastest option. However, as this
+ service type won't propagate service start-up failures and doesn't allow ordering of other units
+ against completion of initialization of the service (which for example is useful if clients need to
+ connect to the service through some form of IPC, and the IPC channel is only established by the
+ service itself — in contrast to doing this ahead of time through socket or bus activation or
+ similar), it might not be sufficient for many cases. If so, <option>notify</option>,
+ <option>notify-reload</option> or <option>dbus</option> (the latter only in case the service
+ provides a D-Bus interface) are the preferred options as they allow service program code to
+ precisely schedule when to consider the service started up successfully and when to proceed with
+ follow-up units. The <option>notify</option>/<option>notify-reload</option> service types require
+ explicit support in the service codebase (as <function>sd_notify()</function> or an equivalent API
+ needs to be invoked by the service at the appropriate time) — if it's not supported, then
+ <option>forking</option> is an alternative: it supports the traditional UNIX service start-up
+ protocol. Finally, <option>exec</option> might be an option for cases where it is enough to ensure
+ the service binary is invoked, and where the service binary itself executes no or little
+ initialization on its own (and its initialization is unlikely to fail). Note that using any type
+ other than <option>simple</option> possibly delays the boot process, as the service manager needs
+ to wait for service initialization to complete. It is hence recommended not to needlessly use any
+ types other than <option>simple</option>. (Also note it is generally not recommended to use
+ <option>idle</option> or <option>oneshot</option> for long-running services.)</para>
</listitem>
</varlistentry>
@@ -319,9 +337,10 @@
the file may not be a symlink to a file owned by a different user (neither directly nor indirectly), and the
PID file must refer to a process already belonging to the service.</para>
- <para>Note that PID files should be avoided in modern projects. Use <option>Type=notify</option> or
- <option>Type=simple</option> where possible, which does not require use of PID files to determine the
- main process of a service and avoids needless forking.</para></listitem>
+ <para>Note that PID files should be avoided in modern projects. Use <option>Type=notify</option>,
+ <option>Type=notify-reload</option> or <option>Type=simple</option> where possible, which does not
+ require use of PID files to determine the main process of a service and avoids needless
+ forking.</para></listitem>
</varlistentry>
<varlistentry>
@@ -443,12 +462,13 @@
with a <literal>-</literal> exit successfully.</para>
<para><varname>ExecStartPost=</varname> commands are only run after the commands specified in
- <varname>ExecStart=</varname> have been invoked successfully, as determined by <varname>Type=</varname>
- (i.e. the process has been started for <varname>Type=simple</varname> or <varname>Type=idle</varname>, the last
- <varname>ExecStart=</varname> process exited successfully for <varname>Type=oneshot</varname>, the initial
- process exited successfully for <varname>Type=forking</varname>, <literal>READY=1</literal> is sent for
- <varname>Type=notify</varname>, or the <varname>BusName=</varname> has been taken for
- <varname>Type=dbus</varname>).</para>
+ <varname>ExecStart=</varname> have been invoked successfully, as determined by
+ <varname>Type=</varname> (i.e. the process has been started for <varname>Type=simple</varname> or
+ <varname>Type=idle</varname>, the last <varname>ExecStart=</varname> process exited successfully for
+ <varname>Type=oneshot</varname>, the initial process exited successfully for
+ <varname>Type=forking</varname>, <literal>READY=1</literal> is sent for
+ <varname>Type=notify</varname>/<varname>Type=notify-reload</varname>, or the
+ <varname>BusName=</varname> has been taken for <varname>Type=dbus</varname>).</para>
<para>Note that <varname>ExecStartPre=</varname> may not be
used to start long-running processes. All processes forked
@@ -487,30 +507,26 @@
<varlistentry>
<term><varname>ExecReload=</varname></term>
- <listitem><para>Commands to execute to trigger a configuration
- reload in the service. This argument takes multiple command
- lines, following the same scheme as described for
- <varname>ExecStart=</varname> above. Use of this setting is
- optional. Specifier and environment variable substitution is
- supported here following the same scheme as for
+
+ <listitem><para>Commands to execute to trigger a configuration reload in the service. This argument
+ takes multiple command lines, following the same scheme as described for
+ <varname>ExecStart=</varname> above. Use of this setting is optional. Specifier and environment
+ variable substitution is supported here following the same scheme as for
<varname>ExecStart=</varname>.</para>
- <para>One additional, special environment variable is set: if
- known, <varname>$MAINPID</varname> is set to the main process
- of the daemon, and may be used for command lines like the
- following:</para>
+ <para>One additional, special environment variable is set: if known, <varname>$MAINPID</varname> is
+ set to the main process of the daemon, and may be used for command lines like the following:</para>
<programlisting>ExecReload=kill -HUP $MAINPID</programlisting>
- <para>Note however that reloading a daemon by sending a signal
- (as with the example line above) is usually not a good choice,
- because this is an asynchronous operation and hence not
- suitable to order reloads of multiple services against each
- other. It is strongly recommended to set
- <varname>ExecReload=</varname> to a command that not only
- triggers a configuration reload of the daemon, but also
- synchronously waits for it to complete. For example,
- <citerefentry project='mankier'><refentrytitle>dbus-broker</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <para>Note however that reloading a daemon by enqueing a signal (as with the example line above) is
+ usually not a good choice, because this is an asynchronous operation and hence not suitable when
+ ordering reloads of multiple services against each other. It is thus strongly recommended to either
+ use <varname>Type=</varname><option>notify-reload</option> in place of
+ <varname>ExecReload=</varname>, or to set <varname>ExecReload=</varname> to a command that not only
+ triggers a configuration reload of the daemon, but also synchronously waits for it to complete. For
+ example, <citerefentry
+ project='mankier'><refentrytitle>dbus-broker</refentrytitle><manvolnum>1</manvolnum></citerefentry>
uses the following:</para>
<programlisting>ExecReload=busctl call org.freedesktop.DBus \
@@ -605,12 +621,13 @@
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
</para>
- <para>If a service of <varname>Type=notify</varname> sends <literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause
- the start time to be extended beyond <varname>TimeoutStartSec=</varname>. The first receipt of this message
- must occur before <varname>TimeoutStartSec=</varname> is exceeded, and once the start time has extended beyond
- <varname>TimeoutStartSec=</varname>, the service manager will allow the service to continue to start, provided
- the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified until the service
- startup status is finished by <literal>READY=1</literal>. (see
+ <para>If a service of <varname>Type=notify</varname>/<varname>Type=notify-reload</varname> sends
+ <literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause the start time to be extended beyond
+ <varname>TimeoutStartSec=</varname>. The first receipt of this message must occur before
+ <varname>TimeoutStartSec=</varname> is exceeded, and once the start time has extended beyond
+ <varname>TimeoutStartSec=</varname>, the service manager will allow the service to continue to start,
+ provided the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified
+ until the service startup status is finished by <literal>READY=1</literal>. (see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
</para></listitem>
</varlistentry>
@@ -633,12 +650,14 @@
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
</para>
- <para>If a service of <varname>Type=notify</varname> sends <literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause
- the stop time to be extended beyond <varname>TimeoutStopSec=</varname>. The first receipt of this message
- must occur before <varname>TimeoutStopSec=</varname> is exceeded, and once the stop time has extended beyond
- <varname>TimeoutStopSec=</varname>, the service manager will allow the service to continue to stop, provided
- the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified, or terminates itself
- (see <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
+ <para>If a service of <varname>Type=notify</varname>/<varname>Type=notify-reload</varname> sends
+ <literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause the stop time to be extended beyond
+ <varname>TimeoutStopSec=</varname>. The first receipt of this message must occur before
+ <varname>TimeoutStopSec=</varname> is exceeded, and once the stop time has extended beyond
+ <varname>TimeoutStopSec=</varname>, the service manager will allow the service to continue to stop,
+ provided the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified,
+ or terminates itself (see
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
</para></listitem>
</varlistentry>
@@ -661,13 +680,15 @@
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
</para>
- <para>If a service of <varname>Type=notify</varname> handles <constant>SIGABRT</constant> itself (instead of relying
- on the kernel to write a core dump) it can send <literal>EXTEND_TIMEOUT_USEC=…</literal> to
- extended the abort time beyond <varname>TimeoutAbortSec=</varname>. The first receipt of this message
- must occur before <varname>TimeoutAbortSec=</varname> is exceeded, and once the abort time has extended beyond
- <varname>TimeoutAbortSec=</varname>, the service manager will allow the service to continue to abort, provided
- the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified, or terminates itself
- (see <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
+ <para>If a service of <varname>Type=notify</varname>/<varname>Type=notify-reload</varname> handles
+ <constant>SIGABRT</constant> itself (instead of relying on the kernel to write a core dump) it can
+ send <literal>EXTEND_TIMEOUT_USEC=…</literal> to extended the abort time beyond
+ <varname>TimeoutAbortSec=</varname>. The first receipt of this message must occur before
+ <varname>TimeoutAbortSec=</varname> is exceeded, and once the abort time has extended beyond
+ <varname>TimeoutAbortSec=</varname>, the service manager will allow the service to continue to abort,
+ provided the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified,
+ or terminates itself (see
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
</para></listitem>
</varlistentry>
@@ -710,12 +731,13 @@
activation completed. Pass <literal>infinity</literal> (the default) to configure no runtime
limit.</para>
- <para>If a service of <varname>Type=notify</varname> sends <literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause
- the runtime to be extended beyond <varname>RuntimeMaxSec=</varname>. The first receipt of this message
- must occur before <varname>RuntimeMaxSec=</varname> is exceeded, and once the runtime has extended beyond
- <varname>RuntimeMaxSec=</varname>, the service manager will allow the service to continue to run, provided
- the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified until the service
- shutdown is achieved by <literal>STOPPING=1</literal> (or termination). (see
+ <para>If a service of <varname>Type=notify</varname>/<varname>Type=notify-reload</varname> sends
+ <literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause the runtime to be extended beyond
+ <varname>RuntimeMaxSec=</varname>. The first receipt of this message must occur before
+ <varname>RuntimeMaxSec=</varname> is exceeded, and once the runtime has extended beyond
+ <varname>RuntimeMaxSec=</varname>, the service manager will allow the service to continue to run,
+ provided the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified
+ until the service shutdown is achieved by <literal>STOPPING=1</literal> (or termination). (see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
</para></listitem>
</varlistentry>
@@ -1023,16 +1045,19 @@
<varlistentry>
<term><varname>NotifyAccess=</varname></term>
<listitem><para>Controls access to the service status notification socket, as accessible via the
- <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> call. Takes one
- of <option>none</option> (the default), <option>main</option>, <option>exec</option> or
- <option>all</option>. If <option>none</option>, no daemon status updates are accepted from the service
- processes, all status update messages are ignored. If <option>main</option>, only service updates sent from the
- main process of the service are accepted. If <option>exec</option>, only service updates sent from any of the
- main or control processes originating from one of the <varname>Exec*=</varname> commands are accepted. If
- <option>all</option>, all services updates from all members of the service's control group are accepted. This
- option should be set to open access to the notification socket when using <varname>Type=notify</varname> or
- <varname>WatchdogSec=</varname> (see above). If those options are used but <varname>NotifyAccess=</varname> is
- not configured, it will be implicitly set to <option>main</option>.</para>
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ call. Takes one of <option>none</option> (the default), <option>main</option>, <option>exec</option>
+ or <option>all</option>. If <option>none</option>, no daemon status updates are accepted from the
+ service processes, all status update messages are ignored. If <option>main</option>, only service
+ updates sent from the main process of the service are accepted. If <option>exec</option>, only
+ service updates sent from any of the main or control processes originating from one of the
+ <varname>Exec*=</varname> commands are accepted. If <option>all</option>, all services updates from
+ all members of the service's control group are accepted. This option should be set to open access to
+ the notification socket when using
+ <varname>Type=notify</varname>/<varname>Type=notify-reload</varname> or
+ <varname>WatchdogSec=</varname> (see above). If those options are used but
+ <varname>NotifyAccess=</varname> is not configured, it will be implicitly set to
+ <option>main</option>.</para>
<para>Note that <function>sd_notify()</function> notifications may be attributed to units correctly only if
either the sending process is still around at the time PID 1 processes the message, or if the sending process
@@ -1156,6 +1181,15 @@
kills, this setting determines the state of the unit after <command>systemd-oomd</command> kills a
cgroup associated with it.</para></listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><varname>ReloadSignal=</varname></term>
+ <listitem><para>Configures the UNIX process signal to send to the service's main process when asked
+ to reload the service's configuration. Defaults to <constant>SIGHUP</constant>. This option has no
+ effect unless <varname>Type=</varname><option>notify-reload</option> is used, see
+ above.</para></listitem>
+ </varlistentry>
+
</variablelist>
<para id='shared-unit-options'>Check
@@ -1319,16 +1353,13 @@ WantedBy=multi-user.target</programlisting>
<citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details.</para>
- <para>Note that this unit type does not include any type of
- notification when a service has completed initialization. For
- this, you should use other unit types, such as
- <varname>Type=</varname><option>notify</option> if the service
- understands systemd's notification protocol,
- <varname>Type=</varname><option>forking</option> if the service
- can background itself or
- <varname>Type=</varname><option>dbus</option> if the unit
- acquires a DBus name once initialization is complete. See
- below.</para>
+ <para>Note that this unit type does not include any type of notification when a service has completed
+ initialization. For this, you should use other unit types, such as
+ <varname>Type=</varname><option>notify</option>/<varname>Type=</varname><option>notify-reload</option>
+ if the service understands systemd's notification protocol,
+ <varname>Type=</varname><option>forking</option> if the service can background itself or
+ <varname>Type=</varname><option>dbus</option> if the unit acquires a DBus name once initialization is
+ complete. See below.</para>
</example>
<example>
@@ -1505,15 +1536,12 @@ SystemdService=simple-dbus-service.service</programlisting>
<example>
<title>Services that notify systemd about their initialization</title>
- <para><varname>Type=</varname><option>simple</option> services
- are really easy to write, but have the major disadvantage of
- systemd not being able to tell when initialization of the given
- service is complete. For this reason, systemd supports a simple
- notification protocol that allows daemons to make systemd aware
- that they are done initializing. Use
- <varname>Type=</varname><option>notify</option> for this. A
- typical service file for such a daemon would look like
- this:</para>
+ <para><varname>Type=</varname><option>simple</option> services are really easy to write, but have the
+ major disadvantage of systemd not being able to tell when initialization of the given service is
+ complete. For this reason, systemd supports a simple notification protocol that allows daemons to make
+ systemd aware that they are done initializing. Use <varname>Type=</varname><option>notify</option> or
+ <varname>Type=</varname><option>notify-reload</option> for this. A typical service file for such a
+ daemon would look like this:</para>
<programlisting>[Unit]
Description=Simple notifying service

View File

@ -0,0 +1,105 @@
From 567b6dcd4ff8e4a9c9b0b1629fa8c015d5e6a724 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 15:01:56 +0100
Subject: [PATCH] pid1: make sure we send our calling service manager
RELOADING=1 when reloading
And send READY=1 again when we are done with it.
We do this not only for "daemon-reload" but also for "daemon-reexec" and
"switch-root", since from the perspective of an encapsulating service
manager these three operations are not that different.
(cherry picked from commit dd0ab174c36492cdcb92cf46844fb0905b1d4a7e)
Related: RHEL-6090
---
src/core/main.c | 10 ++++++++++
src/core/manager.c | 12 ++++++++++++
src/core/manager.h | 1 +
units/user@.service.in | 2 +-
4 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/src/core/main.c b/src/core/main.c
index 0e2e5448bb..126a4bce8c 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -1925,6 +1925,8 @@ static int invoke_main_loop(
LogTarget saved_log_target;
int saved_log_level;
+ manager_send_reloading(m);
+
log_info("Reloading.");
/* First, save any overridden log level/target, then parse the configuration file,
@@ -1955,6 +1957,10 @@ static int invoke_main_loop(
}
case MANAGER_REEXECUTE:
+
+ manager_send_reloading(m); /* From the perspective of the manager calling us this is
+ * pretty much the same as a reload */
+
r = prepare_reexecute(m, &arg_serialization, ret_fds, false);
if (r < 0) {
*ret_error_message = "Failed to prepare for reexecution";
@@ -1970,6 +1976,10 @@ static int invoke_main_loop(
return objective;
case MANAGER_SWITCH_ROOT:
+
+ manager_send_reloading(m); /* From the perspective of the manager calling us this is
+ * pretty much the same as a reload */
+
manager_set_switching_root(m, true);
if (!m->switch_root_init) {
diff --git a/src/core/manager.c b/src/core/manager.c
index 6371810ce3..b34103d7d3 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -3641,6 +3641,18 @@ void manager_check_finished(Manager *m) {
manager_invalidate_startup_units(m);
}
+void manager_send_reloading(Manager *m) {
+ assert(m);
+
+ /* Let whoever invoked us know that we are now reloading */
+ (void) sd_notifyf(/* unset= */ false,
+ "RELOADING=1\n"
+ "MONOTONIC_USEC=" USEC_FMT "\n", now(CLOCK_MONOTONIC));
+
+ /* And ensure that we'll send READY=1 again as soon as we are ready again */
+ m->ready_sent = false;
+}
+
static bool generator_path_any(const char* const* paths) {
bool found = false;
diff --git a/src/core/manager.h b/src/core/manager.h
index 75c16d6e26..87e63c3b68 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -535,6 +535,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u);
bool manager_unit_inactive_or_pending(Manager *m, const char *name);
void manager_check_finished(Manager *m);
+void manager_send_reloading(Manager *m);
void disable_printk_ratelimit(void);
void manager_recheck_dbus(Manager *m);
diff --git a/units/user@.service.in b/units/user@.service.in
index efbd5dfbc8..2c99f50905 100644
--- a/units/user@.service.in
+++ b/units/user@.service.in
@@ -17,7 +17,7 @@ IgnoreOnIsolate=yes
[Service]
User=%i
PAMName=systemd-user
-Type=notify
+Type=notify-reload
ExecStart={{ROOTLIBEXECDIR}}/systemd --user
Slice=user-%i.slice
KillMode=mixed

View File

@ -0,0 +1,166 @@
From fef242735b987c1870bcd0460cc0c802e78a3cde Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 17:25:46 +0100
Subject: [PATCH] networkd: implement Type=notify-reload protocol
(cherry picked from commit 0e07cdb0e77d0322bc866b5e13abbe38e988059d)
Related: RHEL-6090
---
src/network/networkd-manager-bus.c | 13 +-------
src/network/networkd-manager.c | 48 ++++++++++++++++++++++++++----
src/network/networkd-manager.h | 2 ++
src/network/networkd.c | 2 --
units/systemd-networkd.service.in | 3 +-
5 files changed, 47 insertions(+), 21 deletions(-)
diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c
index 2ab3aaadc2..67f951df69 100644
--- a/src/network/networkd-manager-bus.c
+++ b/src/network/networkd-manager-bus.c
@@ -197,7 +197,6 @@ static int bus_method_reconfigure_link(sd_bus_message *message, void *userdata,
static int bus_method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *manager = userdata;
- Link *link;
int r;
r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
@@ -209,20 +208,10 @@ static int bus_method_reload(sd_bus_message *message, void *userdata, sd_bus_err
if (r == 0)
return 1; /* Polkit will call us back */
- r = netdev_load(manager, true);
+ r = manager_reload(manager);
if (r < 0)
return r;
- r = network_reload(manager);
- if (r < 0)
- return r;
-
- HASHMAP_FOREACH(link, manager->links_by_index) {
- r = link_reconfigure(link, /* force = */ false);
- if (r < 0)
- return r;
- }
-
return sd_bus_reply_method_return(message, NULL);
}
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index cdfd29bc0e..362ee84b09 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -483,6 +483,14 @@ static int signal_restart_callback(sd_event_source *s, const struct signalfd_sig
return sd_event_exit(sd_event_source_get_event(s), 0);
}
+static int signal_reload_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+ Manager *m = ASSERT_PTR(userdata);
+
+ manager_reload(m);
+
+ return 0;
+}
+
static int manager_set_keep_configuration(Manager *m) {
int r;
@@ -517,12 +525,11 @@ int manager_setup(Manager *m) {
if (r < 0)
return r;
- assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR2, -1) >= 0);
-
(void) sd_event_set_watchdog(m->event, true);
- (void) sd_event_add_signal(m->event, NULL, SIGTERM, signal_terminate_callback, m);
- (void) sd_event_add_signal(m->event, NULL, SIGINT, signal_terminate_callback, m);
- (void) sd_event_add_signal(m->event, NULL, SIGUSR2, signal_restart_callback, m);
+ (void) sd_event_add_signal(m->event, NULL, SIGTERM | SD_EVENT_SIGNAL_PROCMASK, signal_terminate_callback, m);
+ (void) sd_event_add_signal(m->event, NULL, SIGINT | SD_EVENT_SIGNAL_PROCMASK, signal_terminate_callback, m);
+ (void) sd_event_add_signal(m->event, NULL, SIGUSR2 | SD_EVENT_SIGNAL_PROCMASK, signal_restart_callback, m);
+ (void) sd_event_add_signal(m->event, NULL, SIGHUP | SD_EVENT_SIGNAL_PROCMASK, signal_reload_callback, m);
r = sd_event_add_post(m->event, NULL, manager_dirty_handler, m);
if (r < 0)
@@ -1078,3 +1085,34 @@ int manager_set_timezone(Manager *m, const char *tz) {
return 0;
}
+
+int manager_reload(Manager *m) {
+ Link *link;
+ int r;
+
+ assert(m);
+
+ (void) sd_notifyf(/* unset= */ false,
+ "RELOADING=1\n"
+ "STATUS=Reloading configuration...\n"
+ "MONOTONIC_USEC=" USEC_FMT, now(CLOCK_MONOTONIC));
+
+ r = netdev_load(m, /* reload= */ true);
+ if (r < 0)
+ goto finish;
+
+ r = network_reload(m);
+ if (r < 0)
+ goto finish;
+
+ HASHMAP_FOREACH(link, m->links_by_index) {
+ r = link_reconfigure(link, /* force = */ false);
+ if (r < 0)
+ goto finish;
+ }
+
+ r = 0;
+finish:
+ (void) sd_notify(/* unset= */ false, NOTIFY_READY);
+ return r;
+}
diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h
index 40e6092f85..e6183af0e4 100644
--- a/src/network/networkd-manager.h
+++ b/src/network/networkd-manager.h
@@ -115,4 +115,6 @@ int manager_enumerate(Manager *m);
int manager_set_hostname(Manager *m, const char *hostname);
int manager_set_timezone(Manager *m, const char *timezone);
+int manager_reload(Manager *m);
+
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
diff --git a/src/network/networkd.c b/src/network/networkd.c
index d61769d9f3..68760e8ff4 100644
--- a/src/network/networkd.c
+++ b/src/network/networkd.c
@@ -81,8 +81,6 @@ static int run(int argc, char *argv[]) {
if (r < 0)
log_warning_errno(r, "Could not create runtime directory 'lldp': %m");
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
-
r = manager_new(&m, /* test_mode = */ false);
if (r < 0)
return log_error_errno(r, "Could not create manager: %m");
diff --git a/units/systemd-networkd.service.in b/units/systemd-networkd.service.in
index d15129e7f0..d8b935a358 100644
--- a/units/systemd-networkd.service.in
+++ b/units/systemd-networkd.service.in
@@ -24,7 +24,6 @@ BusName=org.freedesktop.network1
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW
DeviceAllow=char-* rw
ExecStart=!!{{ROOTLIBEXECDIR}}/systemd-networkd
-ExecReload=networkctl reload
FileDescriptorStoreMax=512
LockPersonality=yes
MemoryDenyWriteExecute=yes
@@ -48,7 +47,7 @@ RuntimeDirectoryPreserve=yes
SystemCallArchitectures=native
SystemCallErrorNumber=EPERM
SystemCallFilter=@system-service
-Type=notify
+Type=notify-reload
User=systemd-network
{{SERVICE_WATCHDOG}}

View File

@ -0,0 +1,127 @@
From daa0a0268e9ed03b8e3c39f003266d0b14cae120 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 17:21:16 +0100
Subject: [PATCH] udevd: implement the full Type=notify-reload protocol
We are basically already there, just need to add MONOTONIC_USEC= to the
RELOADING=1 message, and make sure the message is generated in really
all cases.
(cherry picked from commit f84331539deae28fbeb42d45ad0c8d583b3372a3)
Related: RHEL-6090
---
src/udev/udevd.c | 47 +++++++++++++++++++---------------
units/systemd-udevd.service.in | 3 +--
2 files changed, 28 insertions(+), 22 deletions(-)
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index ccc3c0eece..6d82a6eff2 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -32,6 +32,7 @@
#include "cgroup-setup.h"
#include "cgroup-util.h"
#include "cpu-set-util.h"
+#include "daemon-util.h"
#include "dev-setup.h"
#include "device-monitor-private.h"
#include "device-private.h"
@@ -331,9 +332,7 @@ static void manager_exit(Manager *manager) {
manager->exit = true;
- sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Starting shutdown...");
+ (void) sd_notify(/* unset= */ false, NOTIFY_STOPPING);
/* close sources of new events and discard buffered events */
manager->ctrl = udev_ctrl_unref(manager->ctrl);
@@ -351,7 +350,7 @@ static void manager_exit(Manager *manager) {
static void notify_ready(void) {
int r;
- r = sd_notifyf(false,
+ r = sd_notifyf(/* unset= */ false,
"READY=1\n"
"STATUS=Processing with %u children at max", arg_children_max);
if (r < 0)
@@ -376,23 +375,33 @@ static void manager_reload(Manager *manager, bool force) {
mac_selinux_maybe_reload();
/* Nothing changed. It is not necessary to reload. */
- if (!udev_rules_should_reload(manager->rules) && !udev_builtin_should_reload())
- return;
+ if (!udev_rules_should_reload(manager->rules) && !udev_builtin_should_reload()) {
- sd_notify(false,
- "RELOADING=1\n"
- "STATUS=Flushing configuration...");
+ if (!force)
+ return;
- manager_kill_workers(manager, false);
+ /* If we eat this up, then tell our service manager to just continue */
+ (void) sd_notifyf(/* unset= */ false,
+ "RELOADING=1\n"
+ "STATUS=Skipping configuration reloading, nothing changed.\n"
+ "MONOTONIC_USEC=" USEC_FMT, now(CLOCK_MONOTONIC));
+ } else {
+ (void) sd_notifyf(/* unset= */ false,
+ "RELOADING=1\n"
+ "STATUS=Flushing configuration...\n"
+ "MONOTONIC_USEC=" USEC_FMT, now(CLOCK_MONOTONIC));
- udev_builtin_exit();
- udev_builtin_init();
+ manager_kill_workers(manager, false);
- r = udev_rules_load(&rules, arg_resolve_name_timing);
- if (r < 0)
- log_warning_errno(r, "Failed to read udev rules, using the previously loaded rules, ignoring: %m");
- else
- udev_rules_free_and_replace(manager->rules, rules);
+ udev_builtin_exit();
+ udev_builtin_init();
+
+ r = udev_rules_load(&rules, arg_resolve_name_timing);
+ if (r < 0)
+ log_warning_errno(r, "Failed to read udev rules, using the previously loaded rules, ignoring: %m");
+ else
+ udev_rules_free_and_replace(manager->rules, rules);
+ }
notify_ready();
}
@@ -1982,9 +1991,7 @@ static int main_loop(Manager *manager) {
if (r < 0)
log_error_errno(r, "Event loop failed: %m");
- sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Shutting down...");
+ (void) sd_notify(/* unset= */ false, NOTIFY_STOPPING);
return r;
}
diff --git a/units/systemd-udevd.service.in b/units/systemd-udevd.service.in
index e9dbe85ef4..dfc2a0e341 100644
--- a/units/systemd-udevd.service.in
+++ b/units/systemd-udevd.service.in
@@ -18,14 +18,13 @@ ConditionPathIsReadWrite=/sys
[Service]
CapabilityBoundingSet=~CAP_SYS_TIME CAP_WAKE_ALARM
Delegate=pids
-Type=notify
+Type=notify-reload
# Note that udev will reset the value internally for its workers
OOMScoreAdjust=-1000
Sockets=systemd-udevd-control.socket systemd-udevd-kernel.socket
Restart=always
RestartSec=0
ExecStart={{ROOTLIBEXECDIR}}/systemd-udevd
-ExecReload=udevadm control --reload --timeout 0
KillMode=mixed
TasksMax=infinity
PrivateMounts=yes

View File

@ -0,0 +1,52 @@
From dd9aa5ffe940ac6d5204a04fce5faafc3fc01924 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 17:35:23 +0100
Subject: [PATCH] logind: implement Type=notify-reload protocol properly
So close already. Let's add the two missing notifications too.
Fixes: #18484
(cherry picked from commit 5d71e463f49518c7702467f6145484afa31bf8ba)
Related: RHEL-6090
---
src/login/logind.c | 6 ++++++
units/systemd-logind.service.in | 1 +
2 files changed, 7 insertions(+)
diff --git a/src/login/logind.c b/src/login/logind.c
index cdca5ca58c..0348b19c05 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -1014,6 +1014,11 @@ static int manager_dispatch_reload_signal(sd_event_source *s, const struct signa
Manager *m = userdata;
int r;
+ (void) sd_notifyf(/* unset= */ false,
+ "RELOADING=1\n"
+ "STATUS=Reloading configuration...\n"
+ "MONOTONIC_USEC=" USEC_FMT, now(CLOCK_MONOTONIC));
+
manager_reset_config(m);
r = manager_parse_config_file(m);
if (r < 0)
@@ -1021,6 +1026,7 @@ static int manager_dispatch_reload_signal(sd_event_source *s, const struct signa
else
log_info("Config file reloaded.");
+ (void) sd_notify(/* unset= */ false, NOTIFY_READY);
return 0;
}
diff --git a/units/systemd-logind.service.in b/units/systemd-logind.service.in
index 042ea75d7a..24f5ddaa17 100644
--- a/units/systemd-logind.service.in
+++ b/units/systemd-logind.service.in
@@ -58,6 +58,7 @@ StateDirectory=systemd/linger
SystemCallArchitectures=native
SystemCallErrorNumber=EPERM
SystemCallFilter=@system-service
+Type=notify-reload
{{SERVICE_WATCHDOG}}
# Increase the default a bit in order to allow many simultaneous logins since

View File

@ -0,0 +1,297 @@
From 2b5c9fceaaa30ec9c2d031c9ca32b71c43f22f98 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 3 Jan 2023 12:55:50 +0100
Subject: [PATCH] notify: add --stopping + --reloading switches
These wrap RELOADING=1 and STOPPING=1 messages. The former is
particularly useful, since we want to insert the MONOTONIC_USEC= field
into the message automatically, which is easy from C but harder from
shell.
(cherry picked from commit fd0f4da5457fbf7136f2d1888142d5fea75fd45a)
Related: RHEL-6090
---
man/systemd-notify.xml | 107 ++++++++++++++++++++++++-----------------
src/notify/notify.c | 39 +++++++++++++--
2 files changed, 97 insertions(+), 49 deletions(-)
diff --git a/man/systemd-notify.xml b/man/systemd-notify.xml
index 1327d23155..a275123d40 100644
--- a/man/systemd-notify.xml
+++ b/man/systemd-notify.xml
@@ -30,34 +30,35 @@
<refsect1>
<title>Description</title>
- <para><command>systemd-notify</command> may be called by daemon
- scripts to notify the init system about status changes. It can be
- used to send arbitrary information, encoded in an
- environment-block-like list of strings. Most importantly, it can be
- used for start-up completion notification.</para>
-
- <para>This is mostly just a wrapper around
- <function>sd_notify()</function> and makes this functionality
+ <para><command>systemd-notify</command> may be called by service scripts to notify the invoking service
+ manager about status changes. It can be used to send arbitrary information, encoded in an
+ environment-block-like list of strings. Most importantly, it can be used for start-up completion
+ notification.</para>
+
+ <para>This is mostly just a wrapper around <function>sd_notify()</function> and makes this functionality
available to shell scripts. For details see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</para>
- <para>The command line may carry a list of environment variables
- to send as part of the status update.</para>
+ <para>The command line may carry a list of environment variables to send as part of the status
+ update.</para>
<para>Note that systemd will refuse reception of status updates from this command unless
<varname>NotifyAccess=</varname> is set for the service unit this command is called from.</para>
- <para>Note that <function>sd_notify()</function> notifications may be attributed to units correctly only if either
- the sending process is still around at the time PID 1 processes the message, or if the sending process is
- explicitly runtime-tracked by the service manager. The latter is the case if the service manager originally forked
- off the process, i.e. on all processes that match <varname>NotifyAccess=</varname><option>main</option> or
- <varname>NotifyAccess=</varname><option>exec</option>. Conversely, if an auxiliary process of the unit sends an
- <function>sd_notify()</function> message and immediately exits, the service manager might not be able to properly
- attribute the message to the unit, and thus will ignore it, even if <varname>NotifyAccess=</varname><option>all
- </option> is set for it. When <option>--no-block</option> is used, all synchronization for reception of notifications
- is disabled, and hence the aforementioned race may occur if the invoking process is not the service manager or spawned
- by the service manager.</para>
+ <para>Note that <function>sd_notify()</function> notifications may be attributed to units correctly only
+ if either the sending process is still around at the time the service manager processes the message, or
+ if the sending process is explicitly runtime-tracked by the service manager. The latter is the case if
+ the service manager originally forked off the process, i.e. on all processes that match
+ <varname>NotifyAccess=</varname><option>main</option> or
+ <varname>NotifyAccess=</varname><option>exec</option>. Conversely, if an auxiliary process of the unit
+ sends an <function>sd_notify()</function> message and immediately exits, the service manager might not be
+ able to properly attribute the message to the unit, and thus will ignore it, even if
+ <varname>NotifyAccess=</varname><option>all</option> is set for it. To address this
+ <command>systemd-notify</command> will wait until the notification message has been processed by the
+ service manager. When <option>--no-block</option> is used, this synchronization for reception of
+ notifications is disabled, and hence the aforementioned race may occur if the invoking process is not the
+ service manager or spawned by the service manager.</para>
<para>Hence, <command>systemd-notify</command> will first attempt to invoke <function>sd_notify()</function>
pretending to have the PID of the invoking process. This will only succeed when invoked with sufficient privileges.
@@ -66,7 +67,6 @@
— appears as sender of the message, which in turn is helpful if the shell process is the main process of a service,
due to the limitations of <varname>NotifyAccess=</varname><option>all</option>. Use the <option>--pid=</option>
switch to tweak this behaviour.</para>
-
</refsect1>
<refsect1>
@@ -78,22 +78,42 @@
<varlistentry>
<term><option>--ready</option></term>
- <listitem><para>Inform the init system about service start-up
- completion. This is equivalent to <command>systemd-notify
- READY=1</command>. For details about the semantics of this
- option see
+ <listitem><para>Inform the invoking service manager about service start-up or configuration reload
+ completion. This is equivalent to <command>systemd-notify READY=1</command>. For details about the
+ semantics of this option see
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--reloading</option></term>
+
+ <listitem><para>Inform the invoking service manager about the beginning of a configuration reload
+ cycle. This is equivalent to <command>systemd-notify RELOADING=1</command> (but implicitly also sets
+ a <varname>MONOTONIC_USEC=</varname> field as required for <varname>Type=notify-reload</varname>
+ services, see
+ <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ for details). For details about the semantics of this option see
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--stopping</option></term>
+
+ <listitem><para>Inform the invoking service manager about the beginning of the shutdown phase of the
+ service. This is equivalent to <command>systemd-notify STOPPING=1</command>. For details about the
+ semantics of this option see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--pid=</option></term>
- <listitem><para>Inform the service manager about the main PID of the daemon. Takes a PID as
+ <listitem><para>Inform the service manager about the main PID of the service. Takes a PID as
argument. If the argument is specified as <literal>auto</literal> or omitted, the PID of the process
that invoked <command>systemd-notify</command> is used, except if that's the service manager. If the
argument is specified as <literal>self</literal>, the PID of the <command>systemd-notify</command>
command itself is used, and if <literal>parent</literal> is specified the calling process' PID is
- used — even if it is the service manager. This is equivalent to <command>systemd-notify
+ used — even if it is the service manager. The latter is equivalent to <command>systemd-notify
MAINPID=$PID</command>. For details about the semantics of this option see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
@@ -110,27 +130,26 @@
<varlistentry>
<term><option>--status=</option></term>
- <listitem><para>Send a free-form status string for the daemon
- to the init systemd. This option takes the status string as
- argument. This is equivalent to <command>systemd-notify
- STATUS=…</command>. For details about the semantics of this
- option see
- <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
+ <listitem><para>Send a free-form human readable status string for the daemon to the service
+ manager. This option takes the status string as argument. This is equivalent to
+ <command>systemd-notify STATUS=…</command>. For details about the semantics of this option see
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>. This
+ information is shown in
+ <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
+ <command>status</command> output, among other places.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--booted</option></term>
- <listitem><para>Returns 0 if the system was booted up with
- systemd, non-zero otherwise. If this option is passed, no
- message is sent. This option is hence unrelated to the other
- options. For details about the semantics of this option, see
+ <listitem><para>Returns 0 if the system was booted up with systemd, non-zero otherwise. If this
+ option is passed, no message is sent. This option is hence unrelated to the other options. For
+ details about the semantics of this option, see
<citerefentry><refentrytitle>sd_booted</refentrytitle><manvolnum>3</manvolnum></citerefentry>. An
alternate way to check for this state is to call
- <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
- with the <command>is-system-running</command> command. It will
- return <literal>offline</literal> if the system was not booted
- with systemd. </para></listitem>
+ <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> with
+ the <command>is-system-running</command> command. It will return <literal>offline</literal> if the
+ system was not booted with systemd. </para></listitem>
</varlistentry>
<varlistentry>
@@ -162,9 +181,8 @@
<example>
<title>Start-up Notification and Status Updates</title>
- <para>A simple shell daemon that sends start-up notifications
- after having set up its communication channel. During runtime it
- sends further status updates to the init system:</para>
+ <para>A simple shell daemon that sends start-up notifications after having set up its communication
+ channel. During runtime it sends further status updates to the init system:</para>
<programlisting>#!/bin/sh
@@ -192,5 +210,4 @@ done</programlisting>
<citerefentry><refentrytitle>sd_booted</refentrytitle><manvolnum>3</manvolnum></citerefentry>
</para>
</refsect1>
-
</refentry>
diff --git a/src/notify/notify.c b/src/notify/notify.c
index 7b23e7bdb0..2d4900a110 100644
--- a/src/notify/notify.c
+++ b/src/notify/notify.c
@@ -23,6 +23,8 @@
#include "util.h"
static bool arg_ready = false;
+static bool arg_reloading = false;
+static bool arg_stopping = false;
static pid_t arg_pid = 0;
static const char *arg_status = NULL;
static bool arg_booted = false;
@@ -42,7 +44,10 @@ static int help(void) {
"\n%sNotify the init system about service status updates.%s\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
- " --ready Inform the init system about service start-up completion\n"
+ " --ready Inform the service manager about service start-up/reload\n"
+ " completion\n"
+ " --reloading Inform the service manager about configuration reloading\n"
+ " --stopping Inform the service manager about service shutdown\n"
" --pid[=PID] Set main PID of daemon\n"
" --uid=USER Set user to send from\n"
" --status=TEXT Set status text\n"
@@ -81,6 +86,8 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_READY = 0x100,
+ ARG_RELOADING,
+ ARG_STOPPING,
ARG_VERSION,
ARG_PID,
ARG_STATUS,
@@ -93,6 +100,8 @@ static int parse_argv(int argc, char *argv[]) {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "ready", no_argument, NULL, ARG_READY },
+ { "reloading", no_argument, NULL, ARG_RELOADING },
+ { "stopping", no_argument, NULL, ARG_STOPPING },
{ "pid", optional_argument, NULL, ARG_PID },
{ "status", required_argument, NULL, ARG_STATUS },
{ "booted", no_argument, NULL, ARG_BOOTED },
@@ -120,6 +129,14 @@ static int parse_argv(int argc, char *argv[]) {
arg_ready = true;
break;
+ case ARG_RELOADING:
+ arg_reloading = true;
+ break;
+
+ case ARG_STOPPING:
+ arg_stopping = true;
+ break;
+
case ARG_PID:
if (isempty(optarg) || streq(optarg, "auto")) {
arg_pid = getppid();
@@ -176,6 +193,8 @@ static int parse_argv(int argc, char *argv[]) {
if (optind >= argc &&
!arg_ready &&
+ !arg_stopping &&
+ !arg_reloading &&
!arg_status &&
!arg_pid &&
!arg_booted) {
@@ -187,10 +206,10 @@ static int parse_argv(int argc, char *argv[]) {
}
static int run(int argc, char* argv[]) {
- _cleanup_free_ char *status = NULL, *cpid = NULL, *n = NULL;
+ _cleanup_free_ char *status = NULL, *cpid = NULL, *n = NULL, *monotonic_usec = NULL;
_cleanup_strv_free_ char **final_env = NULL;
- char* our_env[4];
- unsigned i = 0;
+ char* our_env[7];
+ size_t i = 0;
pid_t source_pid;
int r;
@@ -212,9 +231,21 @@ static int run(int argc, char* argv[]) {
return r <= 0;
}
+ if (arg_reloading) {
+ our_env[i++] = (char*) "RELOADING=1";
+
+ if (asprintf(&monotonic_usec, "MONOTONIC_USEC=" USEC_FMT, now(CLOCK_MONOTONIC)) < 0)
+ return log_oom();
+
+ our_env[i++] = monotonic_usec;
+ }
+
if (arg_ready)
our_env[i++] = (char*) "READY=1";
+ if (arg_stopping)
+ our_env[i++] = (char*) "STOPPING=1";
+
if (arg_status) {
status = strjoin("STATUS=", arg_status);
if (!status)

View File

@ -0,0 +1,74 @@
From 3a2cb37fdbe4e761ae649716f6f8f71feffdd608 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 3 Jan 2023 12:56:53 +0100
Subject: [PATCH] test: add Type=notify-reload testcase
(cherry picked from commit ee52bbc68f129cfed833990906c0a0a77ee12c42)
Related: RHEL-6090
---
test/units/testsuite-59.sh | 51 ++++++++++++++++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/test/units/testsuite-59.sh b/test/units/testsuite-59.sh
index 83db053107..475766a851 100755
--- a/test/units/testsuite-59.sh
+++ b/test/units/testsuite-59.sh
@@ -83,6 +83,57 @@ systemctl start testservice-abort-restart-59.service
systemctl --signal=SIGABRT kill testservice-abort-restart-59.service
wait_on_state_or_fail "testservice-abort-restart-59.service" "failed" "30"
+# Let's now test the notify-reload logic
+
+cat >/run/notify-reload-test.sh <<EOF
+#!/usr/bin/env bash
+set -eux
+set -o pipefail
+
+EXIT_STATUS=88
+LEAVE=0
+
+function reload() {
+ systemd-notify --reloading --status="Adding 11 to exit status"
+ EXIT_STATUS=\$((\$EXIT_STATUS + 11))
+ systemd-notify --ready --status="Back running"
+}
+
+function leave() {
+ systemd-notify --stopping --status="Adding 7 to exit status"
+ EXIT_STATUS=\$((\$EXIT_STATUS + 7))
+ LEAVE=1
+ return 0
+}
+
+trap reload SIGHUP
+trap leave SIGTERM
+
+systemd-notify --ready
+systemd-notify --status="Running now"
+
+while [ \$LEAVE = 0 ] ; do
+ sleep 1
+done
+
+systemd-notify --status="Adding 3 to exit status"
+EXIT_STATUS=\$((\$EXIT_STATUS + 3))
+exit \$EXIT_STATUS
+EOF
+
+chmod +x /run/notify-reload-test.sh
+
+systemd-analyze log-level debug
+
+systemd-run --unit notify-reload-test -p Type=notify-reload -p KillMode=process /run/notify-reload-test.sh
+systemctl reload notify-reload-test
+systemctl stop notify-reload-test
+
+test "$(systemctl show -p ExecMainStatus --value notify-reload-test)" = 109
+
+systemctl reset-failed notify-reload-test
+rm /run/notify-reload-test.sh
+
systemd-analyze log-level info
echo OK >/testok

45
0449-update-TODO.patch Normal file
View File

@ -0,0 +1,45 @@
From 3fa498dba2e67c1c97f25b093ec6c36e55023259 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 16:48:51 +0100
Subject: [PATCH] update TODO
(cherry picked from commit 6fee784964b2763bd4307181335a433078ba977c)
Related: RHEL-6090
---
TODO | 15 +++------------
1 file changed, 3 insertions(+), 12 deletions(-)
diff --git a/TODO b/TODO
index 66c008bff3..8c67f93f35 100644
--- a/TODO
+++ b/TODO
@@ -700,17 +700,9 @@ Features:
and synthesize initrd from it, and measure it. Signing is not necessary, as
microcode does that on its own. Pass as first initrd to kernel.
-* Add a new service type very similar to Type=notify, that goes one step
- further and extends the protocol to cover reloads. Specifically, SIGHUP will
- become the official way to reload, and daemon has to respond with sd_notify()
- to report when it starts reloading, and when it is complete reloading. Care
- must be taken to remove races from this model. I.e. PID 1 needs to take
- CLOCK_MONOTONIC, then send SIGHUP, then wait for at least one RELOADING=1
- message that comes with a newer timestamp, then wait for a READY=1 message.
- while we are at it, also maybe extend the logic to require handling of some
- specific SIGRT signal for setting debug log level, that carries the level via
- the sigqueue() data parameter. With that we extended with minimal logic the
- service runtime logic quite substantially.
+* Maybe extend the service protocol to support handling of some specific SIGRT
+ signal for setting service log level, that carries the level via the
+ sigqueue() data parameter. Enable this via unit file setting.
* firstboot: maybe just default to C.UTF-8 locale if nothing is set, so that we
don't query this unnecessarily in entirely uninitialized
@@ -1738,7 +1730,6 @@ Features:
* unit files:
- allow port=0 in .socket units
- maybe introduce ExecRestartPre=
- - add ReloadSignal= for configuring a reload signal to use
- implement Register= switch in .socket units to enable registration
in Avahi, RPC and other socket registration services.
- allow Type=simple with PIDFile=

View File

@ -0,0 +1,40 @@
From 036f0593b33ddc0f40a333d790a276c3cffe862e Mon Sep 17 00:00:00 2001
From: msizanoen1 <msizanoen@qtmlabs.xyz>
Date: Tue, 2 May 2023 16:59:07 +0700
Subject: [PATCH] core: check for SERVICE_RELOAD_NOTIFY in
manager_dbus_is_running
This ensures that systemd won't erronously disconnect from the system
bus in case a bus recheck is triggered immediately after the bus service
emits `RELOADING=1`.
This fixes an issue where systemd-logind sometimes randomly stops
receiving `UnitRemoved` after a system update.
This also handles SERVICE_RELOAD_SIGNAL just in case somebody ever
creates a D-Bus broker implementation that uses `Type=notify-reload`.
(cherry picked from commit 845824acddf2e7e08c94afe7cfee6e50a682c947)
Related: RHEL-6090
---
src/core/manager.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/core/manager.c b/src/core/manager.c
index b34103d7d3..eeee395b90 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1696,7 +1696,11 @@ static bool manager_dbus_is_running(Manager *m, bool deserialized) {
u = manager_get_unit(m, SPECIAL_DBUS_SERVICE);
if (!u)
return false;
- if (!IN_SET((deserialized ? SERVICE(u)->deserialized_state : SERVICE(u)->state), SERVICE_RUNNING, SERVICE_RELOAD))
+ if (!IN_SET((deserialized ? SERVICE(u)->deserialized_state : SERVICE(u)->state),
+ SERVICE_RUNNING,
+ SERVICE_RELOAD,
+ SERVICE_RELOAD_NOTIFY,
+ SERVICE_RELOAD_SIGNAL))
return false;
return true;

View File

@ -21,7 +21,7 @@
Name: systemd
Url: https://systemd.io
Version: 252
Release: 20%{?dist}
Release: 21%{?dist}
# For a breakdown of the licensing, see README
License: LGPLv2+ and MIT and GPLv2+
Summary: System and Service Manager
@ -509,6 +509,25 @@ Patch0428: 0428-tree-wide-unify-how-we-pick-OS-pretty-name-to-displa.patch
Patch0429: 0429-bootctl-uki-several-follow-ups-for-inspect_osrel.patch
Patch0430: 0430-bootctl-Add-missing-m.patch
Patch0431: 0431-bootctl-tweak-DOS-header-magic-check.patch
Patch0432: 0432-meson-fix-installation-of-ukify.patch
Patch0433: 0433-sd-id128-introduce-id128_hash_ops_free.patch
Patch0434: 0434-udevadm-trigger-allow-to-fallback-without-synthetic-.patch
Patch0435: 0435-udevadm-trigger-settle-with-synthetic-UUID-if-the-ke.patch
Patch0436: 0436-udevadm-trigger-also-check-with-the-original-syspath.patch
Patch0437: 0437-test-use-udevadm-trigger-settle-even-if-device-is-re.patch
Patch0438: 0438-sd-event-don-t-mistake-USEC_INFINITY-passed-in-for-o.patch
Patch0439: 0439-pid1-rework-service_arm_timer-to-optionally-take-a-r.patch
Patch0440: 0440-manager-add-one-more-assert.patch
Patch0441: 0441-pid1-add-new-Type-notify-reload-service-type.patch
Patch0442: 0442-man-document-Type-notify-reload.patch
Patch0443: 0443-pid1-make-sure-we-send-our-calling-service-manager-R.patch
Patch0444: 0444-networkd-implement-Type-notify-reload-protocol.patch
Patch0445: 0445-udevd-implement-the-full-Type-notify-reload-protocol.patch
Patch0446: 0446-logind-implement-Type-notify-reload-protocol-properl.patch
Patch0447: 0447-notify-add-stopping-reloading-switches.patch
Patch0448: 0448-test-add-Type-notify-reload-testcase.patch
Patch0449: 0449-update-TODO.patch
Patch0450: 0450-core-check-for-SERVICE_RELOAD_NOTIFY-in-manager_dbus.patch
# Downstream-only patches (90009999)
@ -1332,6 +1351,27 @@ getent passwd systemd-oom &>/dev/null || useradd -r -l -g systemd-oom -d / -s /s
%files standalone-sysusers -f .file-list-standalone-sysusers
%changelog
* Mon Dec 11 2023 systemd maintenance team <systemd-maint@redhat.com> - 252-21
- meson: fix installation of ukify (RHEL-13199)
- sd-id128: introduce id128_hash_ops_free (RHEL-5988)
- udevadm-trigger: allow to fallback without synthetic UUID only first time (RHEL-5988)
- udevadm-trigger: settle with synthetic UUID if the kernel support it (RHEL-5988)
- udevadm-trigger: also check with the original syspath if device is renamed (RHEL-5988)
- test: use 'udevadm trigger --settle' even if device is renamed (RHEL-5988)
- sd-event: don't mistake USEC_INFINITY passed in for overflow (RHEL-6090)
- pid1: rework service_arm_timer() to optionally take a relative time value (RHEL-6090)
- manager: add one more assert() (RHEL-6090)
- pid1: add new Type=notify-reload service type (RHEL-6090)
- man: document Type=notify-reload (RHEL-6090)
- pid1: make sure we send our calling service manager RELOADING=1 when reloading (RHEL-6090)
- networkd: implement Type=notify-reload protocol (RHEL-6090)
- udevd: implement the full Type=notify-reload protocol (RHEL-6090)
- logind: implement Type=notify-reload protocol properly (RHEL-6090)
- notify: add --stopping + --reloading switches (RHEL-6090)
- test: add Type=notify-reload testcase (RHEL-6090)
- update TODO (RHEL-6090)
- core: check for SERVICE_RELOAD_NOTIFY in manager_dbus_is_running (RHEL-6090)
* Fri Dec 08 2023 systemd maintenance team <systemd-maint@redhat.com> - 252-20
- udev/net: allow new link name as an altname before renaming happens (RHEL-5988)
- sd-netlink: do not swap old name and alternative name (RHEL-5988)