summaryrefslogtreecommitdiffstats
path: root/src/run
diff options
context:
space:
mode:
authorLuca Boccassi <bluca@debian.org>2024-03-27 22:14:15 +0100
committerYu Watanabe <watanabe.yu+github@gmail.com>2024-03-28 03:19:46 +0100
commited358516937780b524a2cfa833427da3df1bc87f (patch)
tree0da580c12f77f32ae511c89201083eeda51c36bb /src/run
parentMerge pull request #31989 from mrc0mmand/test-loop-dev-check (diff)
downloadsystemd-ed358516937780b524a2cfa833427da3df1bc87f.tar.xz
systemd-ed358516937780b524a2cfa833427da3df1bc87f.zip
run: fix generated unit name clash after soft-reboot
When sd-run connects to D-Bus rather than the private socket, it will generate the transient unit name using the bus ID assigned by the D-Bus broker/daemon. The issue is that this ID is only unique per D-Bus run, if the broker/daemon restarts it starts again from 1, and it's a simple incremental counter for each client. So if a transient unit run-u6.service starts and fails, and it is not collected (default on failure), and the system soft-reboots, any new transient unit might conflict as the counter will restart: Failed to start transient service unit: Unit run-u6.service was already loaded or has a fragment file. Get the soft-reboot counter, and if it's greater than zero, append it to the autogenerated unit name to avoid clashes.
Diffstat (limited to 'src/run')
-rw-r--r--src/run/run.c21
1 files changed, 18 insertions, 3 deletions
diff --git a/src/run/run.c b/src/run/run.c
index 7f40ed0076..9349bfafbc 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -1313,6 +1313,7 @@ static int transient_timer_set_properties(sd_bus_message *m) {
}
static int make_unit_name(sd_bus *bus, UnitType t, char **ret) {
+ unsigned soft_reboots_count = 0;
const char *unique, *id;
char *p;
int r;
@@ -1351,9 +1352,23 @@ static int make_unit_name(sd_bus *bus, UnitType t, char **ret) {
"Unique name %s has unexpected format.",
unique);
- p = strjoin("run-u", id, ".", unit_type_to_string(t));
- if (!p)
- return log_oom();
+ /* The unique D-Bus names are actually unique per D-Bus instance, so on soft-reboot they will wrap
+ * and start over since the D-Bus broker is restarted. If there's a failed unit left behind that
+ * hasn't been garbage collected, we'll conflict. Append the soft-reboot counter to avoid clashing. */
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ r = bus_get_property_trivial(
+ bus, bus_systemd_mgr, "SoftRebootsCount", &error, 'u', &soft_reboots_count);
+ if (r < 0)
+ log_debug_errno(r, "Failed to get SoftRebootsCount property, ignoring: %s", bus_error_message(&error, r));
+
+ if (soft_reboots_count > 0) {
+ if (asprintf(&p, "run-u%s-s%u.%s", id, soft_reboots_count, unit_type_to_string(t)) < 0)
+ return log_oom();
+ } else {
+ p = strjoin("run-u", id, ".", unit_type_to_string(t));
+ if (!p)
+ return log_oom();
+ }
*ret = p;
return 0;